diff --git a/MobileUITestPlan-iPhone.xctestplan b/MobileUITestPlan-iPhone.xctestplan index 66ff8224..8378fa26 100644 --- a/MobileUITestPlan-iPhone.xctestplan +++ b/MobileUITestPlan-iPhone.xctestplan @@ -17,6 +17,7 @@ "selectedTests" : [ "RxCodeMobileUITests\/testLaunchesPastPairingIntoMainUI()", "iPhoneNavigationUITests\/testBriefingFlowReturnsToDetailAfterBack()", + "iPhoneNavigationUITests\/testNewThreadFromBriefingDetailOpensChat()", "iPhoneNavigationUITests\/testProjectsFlowReturnsToThreadListAfterBack()" ], "target" : { diff --git a/Packages/Package.swift b/Packages/Package.swift index b647129a..0101f25a 100644 --- a/Packages/Package.swift +++ b/Packages/Package.swift @@ -10,6 +10,7 @@ let package = Package( .library(name: "RxCodeCore", targets: ["RxCodeCore"]), .library(name: "RxCodeChatKit", targets: ["RxCodeChatKit"]), .library(name: "RxCodeSync", targets: ["RxCodeSync"]), + .library(name: "DiffView", targets: ["DiffView"]), ], dependencies: [ .package(url: "https://github.com/nalexn/ViewInspector", from: "0.10.0"), @@ -31,6 +32,7 @@ let package = Package( .target( name: "RxCodeChatKit", dependencies: [ + "DiffView", "MessageList", "RxCodeCore", .product(name: "Textual", package: "textual"), @@ -49,6 +51,19 @@ let package = Package( dependencies: ["RxCodeCore"], path: "Sources/RxCodeSync" ), + .target( + name: "DiffView", + dependencies: ["RxCodeCore"], + path: "Sources/DiffView", + swiftSettings: [ + .defaultIsolation(MainActor.self), + ] + ), + .testTarget( + name: "DiffViewTests", + dependencies: ["DiffView", "RxCodeCore"], + path: "Tests/DiffViewTests" + ), .testTarget( name: "MessageListTests", dependencies: [ diff --git a/Packages/Sources/DiffView/DiffComputation.swift b/Packages/Sources/DiffView/DiffComputation.swift new file mode 100644 index 00000000..9c3667ca --- /dev/null +++ b/Packages/Sources/DiffView/DiffComputation.swift @@ -0,0 +1,264 @@ +import Foundation +import RxCodeCore + +/// Pure, non-isolated diff builders. Lifted out of the macOS-only +/// `FileDiffView` so mobile and any other surface can share the exact same +/// computation pipeline. +public enum DiffComputation { + + // MARK: - Hunks → DiffLine + + /// Renders a series of old/new replacement hunks as a removed-then-added + /// block. Multiple hunks get a separator header. Common leading indentation + /// is stripped so the diff doesn't visually shift right. + /// + /// A hunk with empty `oldString` (file creation) renders as all-green `+` + /// lines numbered from 1 — no spurious empty `-` row. A hunk with empty + /// `newString` (file deletion) renders as all-red `-` lines numbered from + /// 1 — no spurious empty `+` row. This keeps the rendered diff in sync + /// with the sidebar's "+N" / "-N" counts. + public nonisolated static func buildEditDiffLines(from hunks: [PreviewFile.EditHunk]) -> [DiffLine] { + var lines: [DiffLine] = [] + // Pure-create / pure-delete numbering is cumulative across hunks so a + // multi-hunk file creation still numbers from 1 → N across the file. + var createNumber = 1 + var deleteNumber = 1 + for (index, hunk) in hunks.enumerated() { + if hunks.count > 1 { + lines.append(DiffLine(text: "@@ edit \(index + 1) of \(hunks.count) @@", kind: .hunk)) + } + let oldLines = contentLines(hunk.oldString) + let newLines = contentLines(hunk.newString) + let (trimmedOld, trimmedNew) = stripCommonIndent(old: oldLines, new: newLines) + + let isPureCreate = oldLines.isEmpty && !newLines.isEmpty + let isPureDelete = !oldLines.isEmpty && newLines.isEmpty + + for text in trimmedOld { + let number = isPureDelete ? deleteNumber : nil + lines.append(DiffLine( + text: "-" + text, + kind: .removed, + oldLineNumber: number, + newLineNumber: nil + )) + if isPureDelete { deleteNumber += 1 } + } + for text in trimmedNew { + let number = isPureCreate ? createNumber : nil + lines.append(DiffLine( + text: "+" + text, + kind: .added, + oldLineNumber: nil, + newLineNumber: number + )) + if isPureCreate { createNumber += 1 } + } + } + return lines + } + + // MARK: - Snapshot ↔ current → DiffLine + + /// Exact unified diff between two full-file snapshots — used when a + /// pre-edit snapshot is available so we never reverse-apply hunks. Both + /// gutter columns get accurate line numbers. + public nonisolated static func buildSnapshotDiffLines(original: String, current: String) -> [DiffLine] { + let originalLines = contentLines(original) + let currentLines = contentLines(current) + return computeUnifiedDiffLines(old: originalLines, new: currentLines) + } + + // MARK: - Hunks reverse-applied to current → DiffLine + + /// Renders the full current file with the supplied hunks highlighted as + /// edits on top of it. Works by reverse-applying each hunk's `newString` → + /// `oldString` against the current content to reconstruct the pre-edit + /// state, then running a line diff against the current lines. Hunks that + /// can't be reverse-applied (pure deletions or hunks whose `newString` is + /// no longer present) become "orphan" hunks rendered at the top with a + /// header so the change still shows up. + public nonisolated static func buildFullFileEditDiffLines( + currentContent: String, + hunks: [PreviewFile.EditHunk] + ) -> [DiffLine] { + let currentLines = contentLines(currentContent) + guard !currentLines.isEmpty else { + return buildEditDiffLines(from: hunks) + } + + var reconstructed = currentContent + var orphans: [PreviewFile.EditHunk] = [] + + for hunk in hunks.reversed() { + if hunk.newString.isEmpty { + if !hunk.oldString.isEmpty { + orphans.insert(hunk, at: 0) + } + continue + } + if let range = reconstructed.range(of: hunk.newString) { + reconstructed.replaceSubrange(range, with: hunk.oldString) + } else if !hunk.oldString.isEmpty { + orphans.insert(hunk, at: 0) + } + } + + let preEditLines = contentLines(reconstructed) + let unifiedLines = computeUnifiedDiffLines(old: preEditLines, new: currentLines) + + guard !orphans.isEmpty else { return unifiedLines } + + var result: [DiffLine] = [] + for (idx, orphan) in orphans.enumerated() { + let header = orphans.count > 1 + ? "@@ unmatched change \(idx + 1)/\(orphans.count) @@" + : "@@ unmatched change @@" + result.append(DiffLine(text: header, kind: .hunk)) + for line in contentLines(orphan.oldString) { + result.append(DiffLine(text: "-\(line)", kind: .removed)) + } + for line in contentLines(orphan.newString) { + result.append(DiffLine(text: "+\(line)", kind: .added)) + } + } + result.append(contentsOf: unifiedLines) + return result + } + + // MARK: - Unified diff text → DiffLine + + /// Parses raw unified-diff text (`git diff` output) into `DiffLine`s with + /// gutter line numbers reconstructed from `@@ ... @@` hunk headers. + public nonisolated static func parseUnifiedDiff(_ raw: String) -> [DiffLine] { + guard !raw.isEmpty else { return [] } + var lines = raw.components(separatedBy: "\n") + if lines.last == "" { lines.removeLast() } + var oldLine = 0 + var newLine = 0 + var result: [DiffLine] = [] + result.reserveCapacity(lines.count) + for line in lines { + if line.hasPrefix("@@") { + if let (o, n) = parseHunkHeader(line) { + oldLine = o + newLine = n + } + result.append(DiffLine(text: line, kind: .hunk)) + } else if line.hasPrefix("+++") || line.hasPrefix("---") || line.hasPrefix("diff ") || line.hasPrefix("index ") { + result.append(DiffLine(text: line, kind: .meta)) + } else if line.hasPrefix("+") { + result.append(DiffLine(text: line, kind: .added, oldLineNumber: nil, newLineNumber: newLine)) + newLine += 1 + } else if line.hasPrefix("-") { + result.append(DiffLine(text: line, kind: .removed, oldLineNumber: oldLine, newLineNumber: nil)) + oldLine += 1 + } else { + result.append(DiffLine(text: line, kind: .context, oldLineNumber: oldLine, newLineNumber: newLine)) + oldLine += 1 + newLine += 1 + } + } + return result + } + + // MARK: - Helpers + + private nonisolated static func parseHunkHeader(_ line: String) -> (oldStart: Int, newStart: Int)? { + let scanner = Scanner(string: line) + scanner.charactersToBeSkipped = nil + guard scanner.scanString("@@") != nil, + scanner.scanString(" -") != nil, + let oldStart = scanner.scanInt() else { return nil } + _ = scanner.scanString(",") + _ = scanner.scanInt() + guard scanner.scanString(" +") != nil, + let newStart = scanner.scanInt() else { return nil } + return (oldStart, newStart) + } + + private nonisolated static func computeUnifiedDiffLines(old: [String], new: [String]) -> [DiffLine] { + let diff = new.difference(from: old) + var removalIndices = Set() + var insertionElements: [Int: String] = [:] + for change in diff { + switch change { + case .remove(let offset, _, _): + removalIndices.insert(offset) + case .insert(let offset, let element, _): + insertionElements[offset] = element + } + } + + var lines: [DiffLine] = [] + var oldIdx = 0 + var newIdx = 0 + + while oldIdx < old.count || newIdx < new.count { + if oldIdx < old.count, removalIndices.contains(oldIdx) { + lines.append(DiffLine( + text: "-\(old[oldIdx])", + kind: .removed, + oldLineNumber: oldIdx + 1, + newLineNumber: nil + )) + oldIdx += 1 + } else if newIdx < new.count, let added = insertionElements[newIdx] { + lines.append(DiffLine( + text: "+\(added)", + kind: .added, + oldLineNumber: nil, + newLineNumber: newIdx + 1 + )) + newIdx += 1 + } else if oldIdx < old.count, newIdx < new.count { + lines.append(DiffLine( + text: " \(new[newIdx])", + kind: .context, + oldLineNumber: oldIdx + 1, + newLineNumber: newIdx + 1 + )) + oldIdx += 1 + newIdx += 1 + } else if oldIdx < old.count { + lines.append(DiffLine( + text: " \(old[oldIdx])", + kind: .context, + oldLineNumber: oldIdx + 1, + newLineNumber: nil + )) + oldIdx += 1 + } else if newIdx < new.count { + lines.append(DiffLine( + text: " \(new[newIdx])", + kind: .context, + oldLineNumber: nil, + newLineNumber: newIdx + 1 + )) + newIdx += 1 + } + } + + return lines + } + + private nonisolated static func contentLines(_ content: String) -> [String] { + guard !content.isEmpty else { return [] } + var lines = content.components(separatedBy: "\n") + if lines.last == "" { lines.removeLast() } + return lines + } + + private nonisolated static func stripCommonIndent(old: [String], new: [String]) -> (old: [String], new: [String]) { + let combined = old + new + let commonIndent = combined + .filter { !$0.allSatisfy(\.isWhitespace) } + .map { $0.prefix(while: { $0 == " " || $0 == "\t" }).count } + .min() ?? 0 + guard commonIndent > 0 else { return (old, new) } + func strip(_ line: String) -> String { + line.count >= commonIndent ? String(line.dropFirst(commonIndent)) : line + } + return (old.map(strip), new.map(strip)) + } +} diff --git a/Packages/Sources/DiffView/DiffLine.swift b/Packages/Sources/DiffView/DiffLine.swift new file mode 100644 index 00000000..a59446a4 --- /dev/null +++ b/Packages/Sources/DiffView/DiffLine.swift @@ -0,0 +1,34 @@ +import Foundation +import SwiftUI + +/// A single rendered diff row. Carries the raw text (including any `+` / `-` +/// marker), its semantic kind, and 1-based line numbers for the GitHub-style +/// two-column gutter. Either gutter column may be `nil` — added rows have no +/// pre-edit number, removed rows have no post-edit number, hunk/meta rows have +/// neither. +public struct DiffLine: Hashable, Sendable { + public enum Kind: Hashable, Sendable { + case added + case removed + case context + case hunk + case meta + } + + public nonisolated let text: String + public nonisolated let kind: Kind + public nonisolated let oldLineNumber: Int? + public nonisolated let newLineNumber: Int? + + public nonisolated init( + text: String, + kind: Kind, + oldLineNumber: Int? = nil, + newLineNumber: Int? = nil + ) { + self.text = text + self.kind = kind + self.oldLineNumber = oldLineNumber + self.newLineNumber = newLineNumber + } +} diff --git a/Packages/Sources/DiffView/DiffView.swift b/Packages/Sources/DiffView/DiffView.swift new file mode 100644 index 00000000..3dc0e7f9 --- /dev/null +++ b/Packages/Sources/DiffView/DiffView.swift @@ -0,0 +1,352 @@ +import SwiftUI +import RxCodeCore + +/// Pure-SwiftUI GitHub-style diff renderer. Works identically on macOS, iOS, +/// and any other SwiftUI platform — no `NSTextView` / `UITextView` involvement. +/// +/// Layout: +/// - Two gutter columns (old / new line numbers) when both sides have line +/// numbers — i.e. an in-place edit. +/// - One gutter column when only one side has line numbers — i.e. a freshly +/// created file (every row is an addition) or a fully removed file. +/// - No gutter at all when no line numbers are present (e.g. hunk-only +/// edit previews). +/// +/// Long lines can be displayed in two modes: +/// - `.wrap` (default): each row wraps to as many visual lines as needed. +/// - `.scroll`: each row is a single line; the body scrolls horizontally +/// while the gutter stays pinned on the left. +/// The caller owns the toggle (typically in a surrounding toolbar) — pass the +/// current mode in as `display`. +public struct DiffView: View { + /// Two ways to handle source lines that are wider than the viewport. + public enum LineDisplay: String, CaseIterable, Sendable { + case wrap + case scroll + } + + private let lines: [DiffLine] + private let showsBackground: Bool + private let display: LineDisplay + private let language: String? + + public init( + lines: [DiffLine], + showsBackground: Bool = true, + display: LineDisplay = .wrap, + language: String? = nil + ) { + self.lines = lines + self.showsBackground = showsBackground + self.display = display + self.language = language + } + + public var body: some View { + let layout = GutterLayout(lines: lines) + content(layout: layout) + .background(showsBackground ? ClaudeTheme.codeBackground : Color.clear) + .textSelection(.enabled) + } + + @ViewBuilder + private func content(layout: GutterLayout) -> some View { + switch display { + case .wrap: + ScrollView(.vertical) { + LazyVStack(alignment: .leading, spacing: 0) { + ForEach(Array(lines.enumerated()), id: \.offset) { _, line in + DiffRow(line: line, layout: layout, wraps: true, language: language) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + case .scroll: + GeometryReader { proxy in + let viewportWidth = max(0, proxy.size.width - layout.width) + ScrollView(.vertical) { + HStack(alignment: .top, spacing: 0) { + // Sticky gutter column — sits outside the horizontal + // scroll so line numbers stay anchored on the left. + LazyVStack(alignment: .leading, spacing: 0) { + ForEach(Array(lines.enumerated()), id: \.offset) { _, line in + DiffRowGutter(line: line, layout: layout) + } + } + // Horizontally scrollable body. Constrain the viewport + // to the visible remainder; otherwise the vertical + // scroll layout can offer an effectively unbounded + // width and leave a large blank gap before the text. + ScrollView(.horizontal, showsIndicators: true) { + LazyVStack(alignment: .leading, spacing: 0) { + ForEach(Array(lines.enumerated()), id: \.offset) { _, line in + DiffRowBody( + line: line, + layout: layout, + wraps: false, + language: language + ) + } + } + .frame(minWidth: viewportWidth, alignment: .leading) + } + .frame(width: viewportWidth, alignment: .leading) + } + .frame(width: proxy.size.width, alignment: .leading) + } + } + } + } +} + +// MARK: - Gutter Layout + +/// Pre-computed gutter sizing. Determined once from the full line set so every +/// row aligns and we know up-front whether to render one column or two. +struct GutterLayout { + let showOld: Bool + let showNew: Bool + let oldDigits: Int + let newDigits: Int + + init(lines: [DiffLine]) { + // GitHub-style behavior: hide the old-line gutter when the diff has no + // removed rows (e.g. a brand-new file, or a pure-addition edit), and + // hide the new-line gutter when the diff has no added rows (e.g. a + // full deletion). Context rows that carry old numbers alone shouldn't + // force a two-column layout — they're just positional info. + let hasRemovals = lines.contains { $0.kind == .removed } + let hasAdditions = lines.contains { $0.kind == .added } + let maxOld = lines.compactMap(\.oldLineNumber).max() ?? 0 + let maxNew = lines.compactMap(\.newLineNumber).max() ?? 0 + self.showOld = hasRemovals && maxOld > 0 + self.showNew = (hasAdditions || !hasRemovals) && maxNew > 0 + self.oldDigits = max(String(max(maxOld, 1)).count, 2) + self.newDigits = max(String(max(maxNew, 1)).count, 2) + } + + var columnCount: Int { + (showOld ? 1 : 0) + (showNew ? 1 : 0) + } + + var width: CGFloat { + (showOld ? columnWidth(digits: oldDigits) : 0) + + (showNew ? columnWidth(digits: newDigits) : 0) + } + + private func columnWidth(digits: Int) -> CGFloat { + CGFloat(digits) * 7.5 + 8 + } +} + +// MARK: - Row (combined) + +/// Combined gutter + marker + content row. Used in `.wrap` mode where there +/// is no horizontal scroll, so a single HStack is sufficient. +private struct DiffRow: View { + let line: DiffLine + let layout: GutterLayout + let wraps: Bool + let language: String? + + var body: some View { + HStack(alignment: .firstTextBaseline, spacing: 0) { + DiffRowGutter(line: line, layout: layout) + DiffRowBody(line: line, layout: layout, wraps: wraps, language: language) + Spacer(minLength: 0) + } + .frame(maxWidth: .infinity, alignment: .leading) + } +} + +// MARK: - Row Gutter + +private struct DiffRowGutter: View { + let line: DiffLine + let layout: GutterLayout + + var body: some View { + let isHeader = line.kind == .hunk || line.kind == .meta + HStack(spacing: 0) { + if layout.showOld { + GutterCell( + number: isHeader ? nil : line.oldLineNumber, + digits: layout.oldDigits, + side: .old + ) + } + if layout.showNew { + GutterCell( + number: isHeader ? nil : line.newLineNumber, + digits: layout.newDigits, + side: .new + ) + } + } + .frame(minHeight: DiffMetrics.rowMinHeight, alignment: .top) + } +} + +// MARK: - Row Metrics + +/// Minimum row height shared between the sticky gutter column and the +/// horizontally scrolling body in `.scroll` mode, so the two columns align +/// row-for-row even though their fonts differ slightly. +enum DiffMetrics { + static var rowMinHeight: CGFloat { + // ~lineHeight(12pt monospaced) + vertical padding(1 + 1). + ClaudeTheme.messageSize(12) * 1.35 + 2 + } +} + +// MARK: - Row Body (marker + text, inlined as one Text) + +private struct DiffRowBody: View { + let line: DiffLine + let layout: GutterLayout + let wraps: Bool + /// File-extension hint (e.g. "swift", "ts") used to syntax-highlight the + /// body text. `nil` skips highlighting and falls back to a flat color. + let language: String? + + var body: some View { + textView + .font(.system(size: ClaudeTheme.messageSize(12), design: .monospaced)) + // Keep the body flush with the gutter — any extra leading padding + // here visually compounds the source code's own indentation and + // makes deeply-nested lines look like they have a "huge gap" from + // the left edge. + .padding(.leading, 0) + .padding(.trailing, 12) + .padding(.vertical, 1) + .fixedSize(horizontal: !wraps, vertical: true) + .frame( + maxWidth: wraps ? .infinity : nil, + minHeight: DiffMetrics.rowMinHeight, + alignment: .leading + ) + .background(rowBackground) + } + + @ViewBuilder + private var textView: some View { + if wraps { + combinedText + .lineLimit(nil) + .multilineTextAlignment(.leading) + } else { + combinedText + .lineLimit(1) + .truncationMode(.tail) + } + } + + /// Marker + body merged into one `Text` so wrapped continuation lines align + /// flush with the `+` / `-` itself, instead of sitting in a phantom column + /// past the marker like they do when marker and body are separate views. + private var combinedText: Text { + let prefix: Text + switch line.kind { + case .added: + prefix = Text("+ ").foregroundStyle(ClaudeTheme.statusSuccess) + case .removed: + prefix = Text("- ").foregroundStyle(ClaudeTheme.statusError) + case .context: + prefix = Text(" ").foregroundStyle(ClaudeTheme.textTertiary) + case .hunk, .meta: + prefix = layout.columnCount > 0 + ? Text(" ").foregroundStyle(ClaudeTheme.textTertiary) + : Text("") + } + return prefix + bodyTextView + } + + /// Body of the row. Uses `SyntaxHighlighter` for code rows when a language + /// is known; falls back to the flat per-kind color otherwise. Hunk and meta + /// rows are never tokenized — they're not source code. + private var bodyTextView: Text { + let isCode = line.kind == .added || line.kind == .removed || line.kind == .context + if isCode, let language, !language.isEmpty { + let attributed = SyntaxHighlighter.highlight( + bodyText, + language: language, + fontSize: ClaudeTheme.messageSize(12) + ) + return Text(attributed) + } + return Text(bodyText).foregroundStyle(textColor) + } + + private var bodyText: String { + let raw = line.text + switch line.kind { + case .added where raw.hasPrefix("+"): + return String(raw.dropFirst()) + case .removed where raw.hasPrefix("-"): + return String(raw.dropFirst()) + case .context where raw.hasPrefix(" "): + return String(raw.dropFirst()) + default: + return raw + } + } + + private var textColor: Color { + switch line.kind { + case .added: return ClaudeTheme.statusSuccess + case .removed: return ClaudeTheme.statusError + case .hunk: return ClaudeTheme.textTertiary + case .meta: return ClaudeTheme.textTertiary + case .context: return ClaudeTheme.textPrimary + } + } + + private var rowBackground: Color { + switch line.kind { + case .added: return ClaudeTheme.statusSuccess.opacity(0.12) + case .removed: return ClaudeTheme.statusError.opacity(0.12) + case .hunk: return ClaudeTheme.surfaceSecondary.opacity(0.6) + case .meta, .context: return .clear + } + } +} + +// MARK: - Gutter Cell + +private struct GutterCell: View { + enum Side { + case old, new + + var help: String { + switch self { + case .old: return "Old line number (before)" + case .new: return "New line number (after)" + } + } + } + + let number: Int? + let digits: Int + let side: Side + + var body: some View { + Text(numberString) + .font(.system(size: ClaudeTheme.messageSize(11), design: .monospaced)) + .foregroundStyle(ClaudeTheme.textTertiary) + .frame(minWidth: width, alignment: .trailing) + .padding(.horizontal, 4) // tight, so the gutter doesn't dominate the row + .padding(.vertical, 1) + .background(ClaudeTheme.surfaceSecondary.opacity(0.35)) + .help(side.help) + .accessibilityLabel(side.help) + } + + private var numberString: String { + number.map(String.init) ?? "" + } + + private var width: CGFloat { + // Roughly the width of `digits` monospaced glyphs at 11pt. + CGFloat(digits) * 7.5 + } +} diff --git a/Packages/Sources/RxCodeChatKit/ChangeDiffView.swift b/Packages/Sources/RxCodeChatKit/ChangeDiffView.swift index 18a16fb3..bf6839b9 100644 --- a/Packages/Sources/RxCodeChatKit/ChangeDiffView.swift +++ b/Packages/Sources/RxCodeChatKit/ChangeDiffView.swift @@ -1,119 +1,62 @@ import SwiftUI import RxCodeCore +@_exported import DiffView /// Full, non-collapsing diff renderer for a single file. Used by the mobile /// "View Changes" detail page, which owns a whole screen and therefore renders /// every diff line. Accepts either a raw unified diff string (git changes) or a /// set of old/new edit-hunk pairs (thread file edits). /// -/// The +/- coloring intentionally mirrors `ToolResultView`'s inline chat diffs. +/// Rendering is delegated to the shared `DiffView` package so mobile and +/// desktop share the same GitHub-style two-column gutter layout. The display +/// mode (`.wrap` / `.scroll`) is owned by the caller — typically wired to a +/// toolbar button in the surrounding view. public struct ChangeDiffView: View { - private enum Source { - case unified(String) - case hunks([PreviewFile.EditHunk]) - } - - private let source: Source + private let lines: [DiffLine] + private let display: DiffView.LineDisplay + private let language: String? /// Renders a raw unified diff, e.g. `git diff` output. - public init(unifiedDiff: String) { - source = .unified(unifiedDiff) + public init(unifiedDiff: String, display: DiffView.LineDisplay = .wrap, language: String? = nil) { + self.lines = DiffComputation.parseUnifiedDiff(unifiedDiff) + self.display = display + self.language = language } /// Renders old/new replacement pairs as a removed-then-added diff. - public init(hunks: [PreviewFile.EditHunk]) { - source = .hunks(hunks) - } - - public var body: some View { - VStack(alignment: .leading, spacing: 0) { - switch source { - case .unified(let diff): - unifiedRows(diff) - case .hunks(let hunks): - hunkRows(hunks) - } - } - .frame(maxWidth: .infinity, alignment: .leading) - .textSelection(.enabled) - } - - // MARK: - Unified diff - - @ViewBuilder - private func unifiedRows(_ diff: String) -> some View { - let lines = diff.components(separatedBy: .newlines) - ForEach(Array(lines.enumerated()), id: \.offset) { index, line in - diffRow( - lineNumber: unifiedLineNumber(line: line, offset: index), - text: line.isEmpty ? " " : line, - color: unifiedColor(line), - background: unifiedBackground(line) - ) - } - } - - // MARK: - Edit hunks - - @ViewBuilder - private func hunkRows(_ hunks: [PreviewFile.EditHunk]) -> some View { - ForEach(Array(hunks.enumerated()), id: \.offset) { index, hunk in - if index > 0 { - Divider().padding(.vertical, 4) - } - let removed = hunk.oldString - .components(separatedBy: .newlines) - .map { ("- " + $0, ClaudeTheme.statusError, ClaudeTheme.statusError.opacity(0.06)) } - let added = hunk.newString - .components(separatedBy: .newlines) - .map { ("+ " + $0, ClaudeTheme.statusSuccess, ClaudeTheme.statusSuccess.opacity(0.06)) } - ForEach(Array((removed + added).enumerated()), id: \.offset) { offset, item in - diffRow(lineNumber: offset + 1, text: item.0, color: item.1, background: item.2) + public init(hunks: [PreviewFile.EditHunk], display: DiffView.LineDisplay = .wrap, language: String? = nil) { + self.lines = DiffComputation.buildEditDiffLines(from: hunks) + self.display = display + self.language = language + } + + /// Renders the diff between a pre-edit snapshot and a post-edit snapshot. + /// Preferred when both snapshots are available — gives an exact, thread- + /// isolated diff with no dependence on hunk anchoring or disk state. + public init(original: String, modified: String, display: DiffView.LineDisplay = .wrap, language: String? = nil) { + self.lines = DiffComputation.buildSnapshotDiffLines(original: original, current: modified) + self.display = display + self.language = language + } + + /// `+/-` counts derived from the same snapshot diff that + /// `init(original:modified:)` renders, so a sidebar row's badges always + /// match what the detail page shows. + public nonisolated static func snapshotStat(original: String, modified: String) -> (added: Int, removed: Int) { + let lines = DiffComputation.buildSnapshotDiffLines(original: original, current: modified) + var added = 0 + var removed = 0 + for line in lines { + switch line.kind { + case .added: added += 1 + case .removed: removed += 1 + default: break } } + return (added, removed) } - // MARK: - Shared row - - private func diffRow(lineNumber: Int? = nil, text: String, color: Color, background: Color) -> some View { - HStack(alignment: .firstTextBaseline, spacing: 8) { - Text(lineNumber.map(String.init) ?? "") - .font(.system(size: ClaudeTheme.messageSize(11), design: .monospaced)) - .foregroundStyle(ClaudeTheme.textTertiary) - .frame(width: 34, alignment: .trailing) - .accessibilityIdentifier("diff-line-number") - - ChatTextContentView( - text, - size: ClaudeTheme.messageSize(12), - design: .monospaced, - color: color - ) - .frame(maxWidth: .infinity, alignment: .leading) - } - .padding(.horizontal, 8) - .padding(.vertical, 1) - .background(background) - } - - private func unifiedLineNumber(line: String, offset: Int) -> Int? { - if line.hasPrefix("diff ") || line.hasPrefix("index ") || line.hasPrefix("---") || line.hasPrefix("+++") || line.hasPrefix("@@") { - return nil - } - return offset + 1 - } - - private func unifiedColor(_ line: String) -> Color { - if line.hasPrefix("+"), !line.hasPrefix("+++") { return ClaudeTheme.statusSuccess } - if line.hasPrefix("-"), !line.hasPrefix("---") { return ClaudeTheme.statusError } - if line.hasPrefix("@@") { return ClaudeTheme.accent } - return ClaudeTheme.textPrimary - } - - private func unifiedBackground(_ line: String) -> Color { - if line.hasPrefix("+"), !line.hasPrefix("+++") { return ClaudeTheme.statusSuccess.opacity(0.06) } - if line.hasPrefix("-"), !line.hasPrefix("---") { return ClaudeTheme.statusError.opacity(0.06) } - if line.hasPrefix("@@") { return ClaudeTheme.accent.opacity(0.08) } - return Color.clear + public var body: some View { + DiffView(lines: lines, showsBackground: false, display: display, language: language) } } diff --git a/Packages/Sources/RxCodeChatKit/ChatMessageListView.swift b/Packages/Sources/RxCodeChatKit/ChatMessageListView.swift index 45008a69..fdbe11a0 100644 --- a/Packages/Sources/RxCodeChatKit/ChatMessageListView.swift +++ b/Packages/Sources/RxCodeChatKit/ChatMessageListView.swift @@ -104,7 +104,7 @@ struct ChatTransientToolSummaryView: View { var body: some View { VStack(alignment: .leading, spacing: 14) { Button { - withAnimation(.easeInOut(duration: 0.2)) { + withAnimation(.spring(response: 0.35, dampingFraction: 0.82)) { isExpanded.toggle() } } label: { @@ -115,9 +115,10 @@ struct ChatTransientToolSummaryView: View { Text(String(format: String(localized: "%lld tools executed", bundle: .module), tools.count)) .font(.system(size: ClaudeTheme.messageSize(13), weight: .medium)) .foregroundStyle(ClaudeTheme.textTertiary) - Image(systemName: isExpanded ? "chevron.up" : "chevron.down") + Image(systemName: "chevron.down") .font(.system(size: ClaudeTheme.messageSize(10), weight: .medium)) .foregroundStyle(ClaudeTheme.textTertiary) + .rotationEffect(.degrees(isExpanded ? 180 : 0)) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 6) @@ -126,10 +127,21 @@ struct ChatTransientToolSummaryView: View { .buttonStyle(.plain) if isExpanded { - ForEach(tools, id: \.id) { toolCall in - ToolResultView(toolCall: toolCall, isMessageStreaming: false) + VStack(alignment: .leading, spacing: 14) { + ForEach(tools, id: \.id) { toolCall in + ToolResultView(toolCall: toolCall, isMessageStreaming: false) + .transition(.asymmetric( + insertion: .opacity.combined(with: .move(edge: .top)), + removal: .opacity + )) + } } + .transition(.asymmetric( + insertion: .opacity.combined(with: .move(edge: .top)), + removal: .opacity.combined(with: .move(edge: .top)) + )) } } + .animation(.spring(response: 0.35, dampingFraction: 0.82), value: isExpanded) } } diff --git a/Packages/Sources/RxCodeChatKit/FileDiffView.swift b/Packages/Sources/RxCodeChatKit/FileDiffView.swift index 8752df26..39dc4fb4 100644 --- a/Packages/Sources/RxCodeChatKit/FileDiffView.swift +++ b/Packages/Sources/RxCodeChatKit/FileDiffView.swift @@ -1,7 +1,7 @@ import SwiftUI #if os(macOS) -import AppKit import RxCodeCore +import DiffView public struct FileDiffView: View { public let filePath: String @@ -9,15 +9,19 @@ public struct FileDiffView: View { public let editHunks: [PreviewFile.EditHunk] public let gitDiffMode: PreviewFile.GitDiffMode? public let showFullFileDiff: Bool - /// Optional pre-edit snapshot. When provided alongside `showFullFileDiff`, - /// the view diffs this snapshot against the current on-disk content - /// directly — bypassing hunk reverse-application. This gives an exact diff - /// even when other agents have concurrently modified the file. + /// Pre-edit snapshot — "before" side of the snapshot-pair diff. public let originalContent: String? + /// Post-edit snapshot captured after this thread's most recent edit + /// tool_result. When non-nil alongside `showFullFileDiff`, the view diffs + /// `originalContent` against this snapshot directly with no disk read, + /// giving a thread-isolated diff that doesn't pick up external concurrent + /// edits. Falls back to original-vs-disk when nil (legacy rows). + public let modifiedContent: String? @Environment(WindowState.self) private var windowState @State private var diffLines: [DiffLine] = [] @State private var isLoading = true @State private var isCopied = false + @State private var diffDisplay: DiffView.LineDisplay = .wrap public init( filePath: String, @@ -25,7 +29,8 @@ public struct FileDiffView: View { editHunks: [PreviewFile.EditHunk] = [], gitDiffMode: PreviewFile.GitDiffMode? = nil, showFullFileDiff: Bool = false, - originalContent: String? = nil + originalContent: String? = nil, + modifiedContent: String? = nil ) { self.filePath = filePath self.fileName = fileName @@ -33,6 +38,7 @@ public struct FileDiffView: View { self.gitDiffMode = gitDiffMode self.showFullFileDiff = showFullFileDiff self.originalContent = originalContent + self.modifiedContent = modifiedContent } public var body: some View { @@ -75,6 +81,19 @@ public struct FileDiffView: View { .background(ClaudeTheme.surfaceSecondary, in: Capsule()) if !diffLines.isEmpty { + Button { + diffDisplay = (diffDisplay == .wrap) ? .scroll : .wrap + } label: { + Image(systemName: diffDisplay == .wrap + ? "arrow.left.and.right" + : "text.alignleft") + .font(.system(size: ClaudeTheme.messageSize(12))) + .foregroundStyle(ClaudeTheme.textSecondary) + } + .buttonStyle(.borderless) + .focusable(false) + .help(diffDisplay == .wrap ? "Switch to horizontal scroll" : "Switch to wrap") + Button { let raw = diffLines.map(\.text).joined(separator: "\n") copyToClipboard(raw, feedback: $isCopied) @@ -129,18 +148,13 @@ public struct FileDiffView: View { .frame(maxWidth: .infinity) .background(ClaudeTheme.codeBackground) } else { - diffContentView - } - } - - private var diffContentView: some View { - DiffTextRenderer(lines: diffLines, language: language) + DiffView( + lines: diffLines, + display: diffDisplay, + language: SyntaxHighlighter.language(forFilename: fileName) + ) .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(ClaudeTheme.codeBackground) - } - - private var language: String { - URL(fileURLWithPath: filePath).pathExtension.lowercased() + } } // MARK: - Diff Sources @@ -149,15 +163,31 @@ public struct FileDiffView: View { isLoading = true defer { isLoading = false } - // Preferred path when both showFullFileDiff and an originalContent - // snapshot are available: diff the snapshot directly against the - // current file contents. This is exact under concurrent edits — no - // hunk reverse-application, no orphan "unmatched change" headers. + // Snapshot-pair path: both originalContent and modifiedContent were + // captured from disk at the right moments (pre-first-edit and + // post-each-edit). Diff them directly — no view-time disk read, no + // contamination from external concurrent edits on the same file. + if showFullFileDiff, let modified = modifiedContent { + let original = originalContent ?? "" + let lines = await Task.detached(priority: .userInitiated) { + DiffComputation.buildSnapshotDiffLines(original: original, current: modified) + }.value + if !lines.isEmpty { + diffLines = lines + return + } + // Snapshot pair collapsed (e.g. original lost its capture race). + // Fall through to the legacy / hunk paths so a real edit still + // shows something instead of an empty "no changes" state. + } + + // Legacy fallback for rows persisted before modifiedContent existed: + // diff the original snapshot against the current on-disk content. if showFullFileDiff, let original = originalContent { let path = filePath diffLines = await Task.detached(priority: .userInitiated) { let current = (try? String(contentsOfFile: path, encoding: .utf8)) ?? "" - return FileDiffView.buildSnapshotDiffLines(original: original, current: current) + return DiffComputation.buildSnapshotDiffLines(original: original, current: current) }.value return } @@ -170,14 +200,14 @@ public struct FileDiffView: View { guard let contents = try? String(contentsOfFile: path, encoding: .utf8) else { return nil } - return FileDiffView.buildFullFileEditDiffLines(currentContent: contents, hunks: hunks) + return DiffComputation.buildFullFileEditDiffLines(currentContent: contents, hunks: hunks) }).value { diffLines = fullFileLines return } diffLines = await Task.detached(priority: .userInitiated) { - FileDiffView.buildEditDiffLines(from: hunks) + DiffComputation.buildEditDiffLines(from: hunks) }.value return } @@ -187,7 +217,7 @@ public struct FileDiffView: View { let contents = (try? String(contentsOfFile: filePath, encoding: .utf8)) ?? "" let hunks = [PreviewFile.EditHunk(oldString: "", newString: contents)] diffLines = await Task.detached(priority: .userInitiated) { - FileDiffView.buildEditDiffLines(from: hunks) + DiffComputation.buildEditDiffLines(from: hunks) }.value return } @@ -209,530 +239,8 @@ public struct FileDiffView: View { } } diffLines = await Task.detached(priority: .userInitiated) { - FileDiffView.parseDiff(raw) + DiffComputation.parseUnifiedDiff(raw) }.value } - - nonisolated static func buildEditDiffLines(from hunks: [PreviewFile.EditHunk]) -> [DiffLine] { - var lines: [DiffLine] = [] - for (index, hunk) in hunks.enumerated() { - if hunks.count > 1 { - lines.append(DiffLine(text: "@@ edit \(index + 1) of \(hunks.count) @@", kind: .hunk)) - } - let (trimmedOld, trimmedNew) = stripCommonIndent( - old: hunk.oldString.components(separatedBy: .newlines), - new: hunk.newString.components(separatedBy: .newlines) - ) - lines.append(contentsOf: trimmedOld.map { DiffLine(text: "-" + $0, kind: .removed) }) - lines.append(contentsOf: trimmedNew.map { DiffLine(text: "+" + $0, kind: .added) }) - } - return lines - } - - nonisolated static func parseDiff(_ raw: String) -> [DiffLine] { - guard !raw.isEmpty else { return [] } - var lines = raw.components(separatedBy: "\n") - if lines.last == "" { lines.removeLast() } - var oldLine = 0 - var newLine = 0 - var result: [DiffLine] = [] - result.reserveCapacity(lines.count) - for line in lines { - if line.hasPrefix("@@") { - if let (o, n) = parseHunkHeader(line) { - oldLine = o - newLine = n - } - result.append(DiffLine(text: line, kind: .hunk)) - } else if line.hasPrefix("+++") || line.hasPrefix("---") || line.hasPrefix("diff ") || line.hasPrefix("index ") { - result.append(DiffLine(text: line, kind: .meta)) - } else if line.hasPrefix("+") { - result.append(DiffLine(text: line, kind: .added, oldLineNumber: nil, newLineNumber: newLine)) - newLine += 1 - } else if line.hasPrefix("-") { - result.append(DiffLine(text: line, kind: .removed, oldLineNumber: oldLine, newLineNumber: nil)) - oldLine += 1 - } else { - result.append(DiffLine(text: line, kind: .context, oldLineNumber: oldLine, newLineNumber: newLine)) - oldLine += 1 - newLine += 1 - } - } - return result - } - - /// Parses a `@@ -oldStart,oldCount +newStart,newCount @@` header and - /// returns the starting line numbers (1-based). Returns nil for malformed - /// headers. - private nonisolated static func parseHunkHeader(_ line: String) -> (oldStart: Int, newStart: Int)? { - // Expected shape: `@@ -[,] +[,] @@ ` - let scanner = Scanner(string: line) - scanner.charactersToBeSkipped = nil - guard scanner.scanString("@@") != nil, - scanner.scanString(" -") != nil, - let oldStart = scanner.scanInt() else { return nil } - _ = scanner.scanString(",") - _ = scanner.scanInt() - guard scanner.scanString(" +") != nil, - let newStart = scanner.scanInt() else { return nil } - return (oldStart, newStart) - } - - nonisolated static func buildFullFileEditDiffLines( - currentContent: String, - hunks: [PreviewFile.EditHunk] - ) -> [DiffLine] { - return buildCurrentContentDiffLines(currentContent: currentContent, hunks: hunks) - } - - /// Build a unified diff between two full-file snapshots. Used when a - /// pre-edit snapshot is available (captured at tool_use time), so we can - /// render an exact diff without ever reverse-applying hunks. - nonisolated static func buildSnapshotDiffLines( - original: String, - current: String - ) -> [DiffLine] { - let originalLines = contentLines(original) - let currentLines = contentLines(current) - return computeUnifiedDiffLines(old: originalLines, new: currentLines) - } - - /// Build a unified diff that shows the full current file with the hunks - /// rendered inline on top of it. Works by reverse-applying each hunk - /// (newString → oldString) against the current content to reconstruct the - /// pre-edit state, then running a proper line diff between the pre-edit - /// and current lines. Hunks that can't be reverse-applied — pure - /// deletions (empty newString) or hunks whose newString no longer appears - /// in the file — become "orphan" hunks rendered at the top with a header, - /// so a deleted line is still visible even though its exact original - /// position can't be recovered. - private nonisolated static func buildCurrentContentDiffLines( - currentContent: String, - hunks: [PreviewFile.EditHunk] - ) -> [DiffLine] { - let currentLines = contentLines(currentContent) - guard !currentLines.isEmpty else { - return buildEditDiffLines(from: hunks) - } - - var reconstructed = currentContent - var orphans: [PreviewFile.EditHunk] = [] - - for hunk in hunks.reversed() { - if hunk.newString.isEmpty { - if !hunk.oldString.isEmpty { - orphans.insert(hunk, at: 0) - } - continue - } - if let range = reconstructed.range(of: hunk.newString) { - reconstructed.replaceSubrange(range, with: hunk.oldString) - } else if !hunk.oldString.isEmpty { - orphans.insert(hunk, at: 0) - } - } - - let preEditLines = contentLines(reconstructed) - let unifiedLines = computeUnifiedDiffLines(old: preEditLines, new: currentLines) - - guard !orphans.isEmpty else { return unifiedLines } - - var result: [DiffLine] = [] - for (idx, orphan) in orphans.enumerated() { - let header = orphans.count > 1 - ? "@@ unmatched change \(idx + 1)/\(orphans.count) @@" - : "@@ unmatched change @@" - result.append(DiffLine(text: header, kind: .hunk)) - for line in contentLines(orphan.oldString) { - result.append(DiffLine(text: "-\(line)", kind: .removed)) - } - for line in contentLines(orphan.newString) { - result.append(DiffLine(text: "+\(line)", kind: .added)) - } - } - result.append(contentsOf: unifiedLines) - return result - } - - private nonisolated static func computeUnifiedDiffLines( - old: [String], - new: [String] - ) -> [DiffLine] { - let diff = new.difference(from: old) - var removalIndices = Set() - var insertionElements: [Int: String] = [:] - for change in diff { - switch change { - case .remove(let offset, _, _): - removalIndices.insert(offset) - case .insert(let offset, let element, _): - insertionElements[offset] = element - } - } - - var lines: [DiffLine] = [] - var oldIdx = 0 - var newIdx = 0 - - while oldIdx < old.count || newIdx < new.count { - if oldIdx < old.count, removalIndices.contains(oldIdx) { - lines.append(DiffLine( - text: "-\(old[oldIdx])", - kind: .removed, - oldLineNumber: oldIdx + 1, - newLineNumber: nil - )) - oldIdx += 1 - } else if newIdx < new.count, let added = insertionElements[newIdx] { - lines.append(DiffLine( - text: "+\(added)", - kind: .added, - oldLineNumber: nil, - newLineNumber: newIdx + 1 - )) - newIdx += 1 - } else if oldIdx < old.count, newIdx < new.count { - lines.append(DiffLine( - text: " \(new[newIdx])", - kind: .context, - oldLineNumber: oldIdx + 1, - newLineNumber: newIdx + 1 - )) - oldIdx += 1 - newIdx += 1 - } else if oldIdx < old.count { - lines.append(DiffLine( - text: " \(old[oldIdx])", - kind: .context, - oldLineNumber: oldIdx + 1, - newLineNumber: nil - )) - oldIdx += 1 - } else if newIdx < new.count { - lines.append(DiffLine( - text: " \(new[newIdx])", - kind: .context, - oldLineNumber: nil, - newLineNumber: newIdx + 1 - )) - newIdx += 1 - } - } - - return lines - } - - private nonisolated static func contentLines(_ content: String) -> [String] { - guard !content.isEmpty else { return [] } - var lines = content.components(separatedBy: "\n") - if lines.last == "" { lines.removeLast() } - return lines - } -} - -// MARK: - Diff Line Model - -struct DiffLine { - enum Kind { - case added, removed, hunk, meta, context - - var foregroundColor: Color { - switch self { - case .added: return ClaudeTheme.statusSuccess - case .removed: return ClaudeTheme.statusError - case .hunk: return ClaudeTheme.textTertiary - case .meta: return ClaudeTheme.textTertiary - case .context: return ClaudeTheme.textPrimary - } - } - } - - let text: String - let kind: Kind - /// 1-based line number in the pre-edit file (left gutter). Nil for added, - /// hunk, meta, or orphan rows that have no pre-edit position. - let oldLineNumber: Int? - /// 1-based line number in the current file (right gutter). Nil for removed, - /// hunk, meta, or orphan rows that have no post-edit position. - let newLineNumber: Int? - - nonisolated init(text: String, kind: Kind, oldLineNumber: Int? = nil, newLineNumber: Int? = nil) { - self.text = text - self.kind = kind - self.oldLineNumber = oldLineNumber - self.newLineNumber = newLineNumber - } -} - -// MARK: - NSTextView-based Renderer (TextKit2) - -private struct DiffTextRenderer: NSViewRepresentable { - let lines: [DiffLine] - let language: String - - func makeCoordinator() -> Coordinator { Coordinator() } - - func makeNSView(context: Context) -> NSScrollView { - let scrollView = NSScrollView() - scrollView.hasVerticalScroller = true - scrollView.hasHorizontalScroller = false - scrollView.autohidesScrollers = true - scrollView.borderType = .noBorder - scrollView.drawsBackground = false - - let textView = NSTextView() - textView.minSize = .zero - textView.maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) - textView.isVerticallyResizable = true - // Disable auto horizontal resize: forces NSTextView to lay out the entire - // document up front to compute frame width. We size the container manually - // so TextKit2's viewport-based vertical layout stays lazy. - textView.isHorizontallyResizable = false - textView.autoresizingMask = [.width] - textView.textContainerInset = NSSize(width: 12, height: 10) - textView.isEditable = false - textView.isSelectable = true - textView.allowsUndo = false - textView.usesFontPanel = false - textView.usesFindBar = false - textView.drawsBackground = false - textView.isAutomaticQuoteSubstitutionEnabled = false - textView.isAutomaticDashSubstitutionEnabled = false - textView.isAutomaticTextReplacementEnabled = false - textView.isAutomaticLinkDetectionEnabled = false - - if let container = textView.textContainer { - // Bounded width = TextKit2 keeps vertical layout lazy (viewport-only), - // long lines wrap to fit visible area, no full-document layout pass. - container.widthTracksTextView = true - container.heightTracksTextView = false - container.containerSize = NSSize( - width: 0, - height: CGFloat.greatestFiniteMagnitude - ) - container.lineFragmentPadding = 0 - } - - scrollView.documentView = textView - context.coordinator.attach(textView: textView, lines: lines, language: language) - return scrollView - } - - func updateNSView(_ scrollView: NSScrollView, context: Context) { - guard let textView = scrollView.documentView as? NSTextView else { return } - context.coordinator.update(textView: textView, lines: lines, language: language) - } - - final class Coordinator { - private weak var textView: NSTextView? - private var lastLines: [DiffLine] = [] - private var lastLanguage: String = "" - private var lastFingerprint: Int = 0 - nonisolated(unsafe) private var themeObserver: NSObjectProtocol? - - deinit { - if let observer = themeObserver { - NotificationCenter.default.removeObserver(observer) - } - } - - func attach(textView: NSTextView, lines: [DiffLine], language: String) { - self.textView = textView - apply(lines: lines, language: language, to: textView) - registerThemeObserver() - } - - func update(textView: NSTextView, lines: [DiffLine], language: String) { - let fp = fingerprint(of: lines, language: language) - if fp == lastFingerprint, textView === self.textView { return } - self.textView = textView - apply(lines: lines, language: language, to: textView) - } - - private func registerThemeObserver() { - guard themeObserver == nil else { return } - themeObserver = NotificationCenter.default.addObserver( - forName: .rxcodeThemeDidChange, - object: nil, - queue: .main - ) { [weak self] _ in - MainActor.assumeIsolated { - guard let self, let tv = self.textView else { return } - self.apply(lines: self.lastLines, language: self.lastLanguage, to: tv) - } - } - } - - private func apply(lines: [DiffLine], language: String, to textView: NSTextView) { - textView.textStorage?.setAttributedString(Self.buildAttributedString(lines: lines, language: language)) - lastLines = lines - lastLanguage = language - lastFingerprint = fingerprint(of: lines, language: language) - } - - private func fingerprint(of lines: [DiffLine], language: String) -> Int { - var hasher = Hasher() - hasher.combine(language) - hasher.combine(lines.count) - if let first = lines.first { - hasher.combine(first.text) - hasher.combine(first.kind) - } - if let last = lines.last, lines.count > 1 { - hasher.combine(last.text) - hasher.combine(last.kind) - } - return hasher.finalize() - } - - private static func buildAttributedString(lines: [DiffLine], language: String) -> NSAttributedString { - let fontSize: CGFloat = 12 - let font = NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular) - let gutterColor = NSColor(ClaudeTheme.textTertiary).withAlphaComponent(0.6) - - // GitHub-style two-column gutter: left = pre-edit line number, - // right = post-edit line number. When one side is entirely empty - // (e.g. a Write that created the file from nothing — every row is - // pure addition), collapse to a single column so we don't waste - // gutter width on a permanently blank lane. - let maxOld = lines.compactMap(\.oldLineNumber).max() ?? 0 - let maxNew = lines.compactMap(\.newLineNumber).max() ?? 0 - let showOld = maxOld > 0 - let showNew = maxNew > 0 - let oldDigits = max(String(maxOld).count, 2) - let newDigits = max(String(maxNew).count, 2) - let oldBlank = String(repeating: " ", count: oldDigits) - let newBlank = String(repeating: " ", count: newDigits) - - let addedBg = NSColor(ClaudeTheme.statusSuccess).withAlphaComponent(0.14) - let removedBg = NSColor(ClaudeTheme.statusError).withAlphaComponent(0.14) - - func pad(_ n: Int?, width: Int, blank: String) -> String { - guard let n else { return blank } - let s = String(n) - if s.count >= width { return s } - return String(repeating: " ", count: width - s.count) + s - } - - func gutterPrefix(for line: DiffLine) -> String { - let isHeader = line.kind == .meta || line.kind == .hunk - switch (showOld, showNew) { - case (true, true): - if isHeader { return oldBlank + " " + newBlank + " " } - return pad(line.oldLineNumber, width: oldDigits, blank: oldBlank) - + " " - + pad(line.newLineNumber, width: newDigits, blank: newBlank) - + " " - case (true, false): - if isHeader { return oldBlank + " " } - return pad(line.oldLineNumber, width: oldDigits, blank: oldBlank) + " " - case (false, true): - if isHeader { return newBlank + " " } - return pad(line.newLineNumber, width: newDigits, blank: newBlank) + " " - case (false, false): - return "" - } - } - - let result = NSMutableAttributedString() - for line in lines { - let prefix = gutterPrefix(for: line) - - let rowBg: NSColor? = { - switch line.kind { - case .added: return addedBg - case .removed: return removedBg - default: return nil - } - }() - - var gutterAttrs: [NSAttributedString.Key: Any] = [ - .font: font, - .foregroundColor: gutterColor, - ] - if let bg = rowBg { gutterAttrs[.backgroundColor] = bg } - result.append(NSAttributedString(string: prefix, attributes: gutterAttrs)) - - let body = buildLineBody(line: line, language: language, font: font, fontSize: fontSize, rowBg: rowBg) - result.append(body) - - var newlineAttrs: [NSAttributedString.Key: Any] = [.font: font] - if let bg = rowBg { newlineAttrs[.backgroundColor] = bg } - result.append(NSAttributedString(string: "\n", attributes: newlineAttrs)) - } - return result - } - - private static func buildLineBody( - line: DiffLine, - language: String, - font: NSFont, - fontSize: CGFloat, - rowBg: NSColor? - ) -> NSAttributedString { - switch line.kind { - case .hunk, .meta: - let text = line.text.isEmpty ? " " : line.text - return NSAttributedString(string: text, attributes: [ - .font: font, - .foregroundColor: NSColor(line.kind.foregroundColor), - ]) - case .added, .removed, .context: - let (marker, content) = splitDiffMarker(line: line) - let out = NSMutableAttributedString() - - if !marker.isEmpty { - let markerColor: NSColor - switch line.kind { - case .added: markerColor = NSColor(ClaudeTheme.statusSuccess) - case .removed: markerColor = NSColor(ClaudeTheme.statusError) - default: markerColor = NSColor(ClaudeTheme.textTertiary) - } - var attrs: [NSAttributedString.Key: Any] = [ - .font: font, - .foregroundColor: markerColor, - ] - if let bg = rowBg { attrs[.backgroundColor] = bg } - out.append(NSAttributedString(string: marker, attributes: attrs)) - } - - let bodyText = content.isEmpty ? " " : content - let highlighted: NSMutableAttributedString - if !language.isEmpty, !content.isEmpty { - highlighted = NSMutableAttributedString( - attributedString: SyntaxHighlighter.highlightNS(bodyText, language: language, fontSize: fontSize) - ) - } else { - highlighted = NSMutableAttributedString(string: bodyText, attributes: [ - .font: font, - .foregroundColor: NSColor(ClaudeTheme.textPrimary), - ]) - } - if let bg = rowBg, highlighted.length > 0 { - highlighted.addAttribute( - .backgroundColor, - value: bg, - range: NSRange(location: 0, length: highlighted.length) - ) - } - out.append(highlighted) - return out - } - } - - private static func splitDiffMarker(line: DiffLine) -> (marker: String, content: String) { - let raw = line.text - switch line.kind { - case .added where raw.hasPrefix("+"): - return ("+", String(raw.dropFirst())) - case .removed where raw.hasPrefix("-"): - return ("-", String(raw.dropFirst())) - case .context where raw.hasPrefix(" "): - return (" ", String(raw.dropFirst())) - default: - return ("", raw) - } - } - } } #endif diff --git a/Packages/Sources/RxCodeChatKit/MessageBubble.swift b/Packages/Sources/RxCodeChatKit/MessageBubble.swift index 3df0d766..b1197031 100644 --- a/Packages/Sources/RxCodeChatKit/MessageBubble.swift +++ b/Packages/Sources/RxCodeChatKit/MessageBubble.swift @@ -592,9 +592,10 @@ struct MessageBubble: View { @State private var expandedTransientGroupIds: Set = [] private func transientToolSummary(groupId: String, tools: [ToolCall]) -> some View { - VStack(alignment: .leading, spacing: 14) { + let isExpanded = expandedTransientGroupIds.contains(groupId) + return VStack(alignment: .leading, spacing: 14) { Button { - withAnimation(.easeInOut(duration: 0.2)) { + withAnimation(.spring(response: 0.35, dampingFraction: 0.82)) { if expandedTransientGroupIds.contains(groupId) { expandedTransientGroupIds.remove(groupId) } else { @@ -602,7 +603,6 @@ struct MessageBubble: View { } } } label: { - let isExpanded = expandedTransientGroupIds.contains(groupId) HStack(spacing: 8) { Image(systemName: "eye.slash") .font(.system(size: ClaudeTheme.messageSize(13))) @@ -610,9 +610,10 @@ struct MessageBubble: View { Text(String(format: String(localized: "%lld tools executed", bundle: .module), tools.count)) .font(.system(size: ClaudeTheme.messageSize(13), weight: .medium)) .foregroundStyle(ClaudeTheme.textTertiary) - Image(systemName: isExpanded ? "chevron.up" : "chevron.down") + Image(systemName: "chevron.down") .font(.system(size: ClaudeTheme.messageSize(10), weight: .medium)) .foregroundStyle(ClaudeTheme.textTertiary) + .rotationEffect(.degrees(isExpanded ? 180 : 0)) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 6) @@ -620,12 +621,23 @@ struct MessageBubble: View { } .buttonStyle(.plain) - if expandedTransientGroupIds.contains(groupId) { - ForEach(tools, id: \.id) { toolCall in - ToolResultView(toolCall: toolCall, isMessageStreaming: false) + if isExpanded { + VStack(alignment: .leading, spacing: 14) { + ForEach(tools, id: \.id) { toolCall in + ToolResultView(toolCall: toolCall, isMessageStreaming: false) + .transition(.asymmetric( + insertion: .opacity.combined(with: .move(edge: .top)), + removal: .opacity + )) + } } + .transition(.asymmetric( + insertion: .opacity.combined(with: .move(edge: .top)), + removal: .opacity.combined(with: .move(edge: .top)) + )) } } + .animation(.spring(response: 0.35, dampingFraction: 0.82), value: isExpanded) } private var bubbleShape: UnevenRoundedRectangle { diff --git a/Packages/Sources/RxCodeChatKit/Resources/Localizable.xcstrings b/Packages/Sources/RxCodeChatKit/Resources/Localizable.xcstrings index 6b67a794..8ca9a95a 100644 --- a/Packages/Sources/RxCodeChatKit/Resources/Localizable.xcstrings +++ b/Packages/Sources/RxCodeChatKit/Resources/Localizable.xcstrings @@ -1,6004 +1,5682 @@ { - "sourceLanguage" : "en", - "strings" : { - "" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "" + "sourceLanguage": "en", + "strings": { + "": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "" } } } }, - " · " : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : " · " + " · ": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": " · " } } } }, - "--" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "--" + "--": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "--" } } } }, - "·" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "·" + "·": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "·" } } } }, - "(no output)" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "(无输出)" + "(no output)": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "(无输出)" } } } }, - "/" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "/" + "/": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "/" } } } }, - "%@ — " : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ — " + "%@ — ": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ — " } } } }, - "%@ %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%1$@ %2$@" + "%@ %@": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "%1$@ %2$@" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$@ %2$@" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$@ %2$@" } } } }, - "%@ in progress" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ 进行中" + "%@ in progress": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 进行中" } } } }, - "%lld" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld" + "%lld": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%lld" } } } }, - "%lld commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%lld commands" + "%lld commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "%lld commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld개 커맨드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "%lld개 커맨드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld 个命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%lld 个命令" } } } }, - "%lld messages queued" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld 条消息已排队" + "%lld messages queued": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%lld 条消息已排队" } } } }, - "%lld shortcuts" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%lld shortcuts" + "%lld shortcuts": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "%lld shortcuts" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld개 단축키" + "ko": { + "stringUnit": { + "state": "translated", + "value": "%lld개 단축키" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld 个快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%lld 个快捷方式" } } } }, - "%lld tools executed" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%lld tools executed" + "%lld tools executed": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "%lld tools executed" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld개 도구 실행됨" + "ko": { + "stringUnit": { + "state": "translated", + "value": "%lld개 도구 실행됨" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已执行 %lld 个工具" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已执行 %lld 个工具" } } } }, - "%lld/%lld" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%1$lld/%2$lld" + "%lld/%lld": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "%1$lld/%2$lld" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$lld/%2$lld" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%1$lld/%2$lld" } } } }, - "%lld%%" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld%%" + "%lld%%": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%lld%%" } } } }, - "+%d more pending" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "+%d more pending" + "+%d more pending": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "+%d more pending" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "还有 %d 个待处理" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "还有 %d 个待处理" } } } }, - "$" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "$" + "$": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "$" } } } }, - "5-hour rate limit" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "5-hour rate limit" + "5-hour rate limit": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "5-hour rate limit" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "5시간 사용량 한도" + "ko": { + "stringUnit": { + "state": "translated", + "value": "5시간 사용량 한도" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "5 小时用量限制" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "5 小时用量限制" } } } }, - "5h" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "5h" + "5h": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "5h" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "5시간" + "ko": { + "stringUnit": { + "state": "translated", + "value": "5시간" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "5小时" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "5小时" } } } }, - "7-day rate limit" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "7-day rate limit" + "7-day rate limit": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "7-day rate limit" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "7일 사용량 한도" + "ko": { + "stringUnit": { + "state": "translated", + "value": "7일 사용량 한도" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "7 天用量限制" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "7 天用量限制" } } } }, - "7d" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "7d" + "7d": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "7d" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "7일" + "ko": { + "stringUnit": { + "state": "translated", + "value": "7일" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "7天" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "7天" } } } }, - "A command with this name already exists." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "A command with this name already exists." + "A command with this name already exists.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "A command with this name already exists." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이미 존재하는 커맨드 이름입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "이미 존재하는 커맨드 이름입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已存在同名命令。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已存在同名命令。" } } } }, - "Accept + Auto" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Accept + Auto" + "Accept + Auto": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Accept + Auto" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "接受 + 自动" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "接受 + 自动" } } } }, - "Accept Ask" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Accept Ask" + "Accept Ask": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Accept Ask" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "接受并询问" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "接受并询问" } } } }, - "Accept Edits" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "接受编辑" + "Accept Edits": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "接受编辑" } } } }, - "accepts input" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "accepts input" + "accepts input": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "accepts input" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력 허용" + "ko": { + "stringUnit": { + "state": "translated", + "value": "입력 허용" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "接受输入" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "接受输入" } } } }, - "Accepts Input" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Accepts Input" + "Accepts Input": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Accepts Input" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력 허용" + "ko": { + "stringUnit": { + "state": "translated", + "value": "입력 허용" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "接受输入" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "接受输入" } } } }, - "acceptsInput: true lets users type additional text after the command." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "acceptsInput: true lets users type additional text after the command." + "acceptsInput: true lets users type additional text after the command.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "acceptsInput: true lets users type additional text after the command." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "acceptsInput: true이면 커맨드 뒤에 추가 텍스트를 입력할 수 있습니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "acceptsInput: true이면 커맨드 뒤에 추가 텍스트를 입력할 수 있습니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "acceptsInput:设为 true 后,用户可以在命令后输入额外文本。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "acceptsInput:设为 true 后,用户可以在命令后输入额外文本。" } } } }, - "Add" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add" + "Add": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Add" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "추가" + "ko": { + "stringUnit": { + "state": "translated", + "value": "추가" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "添加" } } } }, - "Add — attach file or toggle plan mode" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加 — 附加文件或切换计划模式" + "Add — attach file or toggle plan mode": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "添加 — 附加文件或切换计划模式" } } } }, - "Add First Shortcut" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add First Shortcut" + "Add First Shortcut": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Add First Shortcut" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "첫 단축키 추가" + "ko": { + "stringUnit": { + "state": "translated", + "value": "첫 단축키 추가" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加第一个快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "添加第一个快捷方式" } } } }, - "Add New Command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add New Command" + "Add New Command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Add New Command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 커맨드 추가" + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 커맨드 추가" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加新命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "添加新命令" } } } }, - "Add New Shortcut" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add New Shortcut" + "Add New Shortcut": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Add New Shortcut" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 단축키 추가" + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 단축키 추가" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加新快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "添加新快捷方式" } } } }, - "Add working directory to session" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add working directory to session" + "Add working directory to session": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Add working directory to session" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "세션에 작업 디렉토리 추가" + "ko": { + "stringUnit": { + "state": "translated", + "value": "세션에 작업 디렉토리 추가" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将工作目录添加到会话" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将工作目录添加到会话" } } } }, - "Agent" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "智能体" + "Agent": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "智能体" } } } }, - "Agent asked %d questions" : { - "comment" : "Inline summary when the assistant invokes AskUserQuestion with multiple questions. %d is the number of questions.", - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "智能体提出了 %d 个问题" + "Agent asked %d questions": { + "comment": "Inline summary when the assistant invokes AskUserQuestion with multiple questions. %d is the number of questions.", + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "智能体提出了 %d 个问题" } } } }, - "Agent asked a question" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "智能体提出了一个问题" + "Agent asked a question": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "智能体提出了一个问题" } } } }, - "agentProvider: agent this command applies to (claudeCode, codex, acp). Use null or omit it for all agents." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "agentProvider: agent this command applies to (claudeCode, codex, acp). Use null or omit it for all agents." + "agentProvider: agent this command applies to (claudeCode, codex, acp). Use null or omit it for all agents.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "agentProvider: agent this command applies to (claudeCode, codex, acp). Use null or omit it for all agents." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "agentProvider:此命令适用的代理(claudeCode、codex、acp)。设为 null 或省略表示适用于所有代理。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "agentProvider:此命令适用的代理(claudeCode、codex、acp)。设为 null 或省略表示适用于所有代理。" } } } }, - "All Agents" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "所有智能体" + "All Agents": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有智能体" } } } }, - "All Agents (Global)" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "所有智能体(全局)" + "All Agents (Global)": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有智能体(全局)" } } } }, - "All modified default commands will be restored to their original state." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "All modified default commands will be restored to their original state." + "All modified default commands will be restored to their original state.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "All modified default commands will be restored to their original state." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "수정한 모든 기본 커맨드가 원래 상태로 복원됩니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "수정한 모든 기본 커맨드가 원래 상태로 복원됩니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "所有修改过的默认命令都会恢复到原始状态。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "所有修改过的默认命令都会恢复到原始状态。" } } } }, - "All properties example:" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "All properties example:" + "All properties example:": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "All properties example:" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모든 속성 예시:" + "ko": { + "stringUnit": { + "state": "translated", + "value": "모든 속성 예시:" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "完整属性示例:" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "完整属性示例:" } } } }, - "Allows additional text to be entered after the command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Allows additional text to be entered after the command" + "Allows additional text to be entered after the command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Allows additional text to be entered after the command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 뒤에 추가 텍스트를 입력할 수 있습니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 뒤에 추가 텍스트를 입력할 수 있습니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "允许在命令后输入额外文本" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "允许在命令后输入额外文本" } } } }, - "Analyze security vulnerabilities" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Analyze security vulnerabilities" + "Analyze security vulnerabilities": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Analyze security vulnerabilities" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 브랜치 변경사항 보안 분석" + "ko": { + "stringUnit": { + "state": "translated", + "value": "현재 브랜치 변경사항 보안 분석" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "分析安全漏洞" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "分析安全漏洞" } } } }, - "Answered" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已回答" + "Answered": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已回答" } } } }, - "Assistant: %@" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "助手:%@" + "Assistant: %@": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "助手:%@" } } } }, - "Attach file" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Attach file" + "Attach file…": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Attach file…" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 첨부" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "附加文件" - } - } - } - }, - "Attach file…" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Attach file…" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "附加文件…" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "附加文件…" } } } }, - "Auto-fix PR CI failures and review comments" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto-fix PR CI failures and review comments" + "Auto-fix PR CI failures and review comments": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Auto-fix PR CI failures and review comments" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "PR CI 실패 및 리뷰 댓글 자동 수정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "PR CI 실패 및 리뷰 댓글 자동 수정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自动修复 PR CI 失败和评审评论" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "自动修复 PR CI 失败和评审评论" } } } }, - "Bash" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bash" + "Bash": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Bash" } } } }, - "Built-in command names are ignored on import and are never exported." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Built-in command names are ignored on import and are never exported." + "Built-in command names are ignored on import and are never exported.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Built-in command names are ignored on import and are never exported." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 명령어 이름은 가져올 때 무시되며 내보내기에 포함되지 않습니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "기본 명령어 이름은 가져올 때 무시되며 내보내기에 포함되지 않습니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "内置命令名称在导入时会被忽略,也不会被导出。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "内置命令名称在导入时会被忽略,也不会被导出。" } } } }, - "Built-in commands are Claude Code only. Custom commands can target one agent or all." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "内置命令仅适用于 Claude Code。自定义命令可以针对一个智能体或全部智能体。" + "Built-in commands are Claude Code only. Custom commands can target one agent or all.": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "内置命令仅适用于 Claude Code。自定义命令可以针对一个智能体或全部智能体。" } } } }, - "Cache creation" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Cache creation" + "Cache creation": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Cache creation" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "캐시 생성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "캐시 생성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "创建缓存" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "创建缓存" } } } }, - "Cache read" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Cache read" + "Cache read": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Cache read" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "캐시 읽기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "캐시 읽기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "读取缓存" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "读取缓存" } } } }, - "Cancel" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Cancel" + "Cancel": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Cancel" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "취소" + "ko": { + "stringUnit": { + "state": "translated", + "value": "취소" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "取消" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "取消" } } } }, - "Change color theme" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Change color theme" + "Change color theme": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Change color theme" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "색상 테마 변경" + "ko": { + "stringUnit": { + "state": "translated", + "value": "색상 테마 변경" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "更改颜色主题" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "更改颜色主题" } } } }, - "Client: %@" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "客户端:%@" + "Client: %@": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "客户端:%@" } } } }, - "Close" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Close" + "Close": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Close" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "닫기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "닫기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "关闭" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "关闭" } } } }, - "Close — you can review later from the banner" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Close — you can review later from the banner" + "Close — you can review later from the banner": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Close — you can review later from the banner" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "关闭 — 之后可从横幅继续查看" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "关闭 — 之后可从横幅继续查看" } } } }, - "Collapse" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Collapse" + "Collapse": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Collapse" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "접기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "접기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "折叠" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "折叠" } } } }, - "Collapse earlier messages" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Collapse earlier messages" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이전 메시지 접기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "折叠较早消息" + "Combine and send all queued messages as a single turn": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将所有排队消息合并为一轮发送" } } } }, - "Combine and send all queued messages as a single turn" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将所有排队消息合并为一轮发送" - } - } - } - }, - "Command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Command" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "命令" - } - } - } - }, - "Command name (e.g. my-command)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Command name (e.g. my-command)" + "Command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 이름 (예: my-command)" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "命令名称(例如 my-command)" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "命令" } } } }, - "Commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Commands" + "Command name (e.g. my-command)": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Command name (e.g. my-command)" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 이름 (예: my-command)" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "命令名称(例如 my-command)" } } } }, - "Commands requiring TUI will run in the inline terminal" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Commands requiring TUI will run in the inline terminal" + "Commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "TUI가 필요한 커맨드는 인라인 터미널에서 실행됩니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "需要 TUI 的命令会在内联终端中运行" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "命令" } } } }, - "Compact conversation (focus instructions allowed)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Compact conversation (focus instructions allowed)" + "Commands requiring TUI will run in the inline terminal": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Commands requiring TUI will run in the inline terminal" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대화 압축 (선택적 포커스 지침 허용)" + "ko": { + "stringUnit": { + "state": "translated", + "value": "TUI가 필요한 커맨드는 인라인 터미널에서 실행됩니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "压缩对话(允许保留重点说明)" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "需要 TUI 的命令会在内联终端中运行" } } } }, - "Completed" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Completed" + "Compact conversation (focus instructions allowed)": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Compact conversation (focus instructions allowed)" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "완료됨" + "ko": { + "stringUnit": { + "state": "translated", + "value": "대화 압축 (선택적 포커스 지침 허용)" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已完成" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "压缩对话(允许保留重点说明)" } } } }, - "Configure Claude in Chrome" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure Claude in Chrome" + "Completed": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Completed" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Chrome에서 Claude 설정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "완료됨" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在 Chrome 中配置 Claude" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已完成" } } } }, - "Configure extra usage" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure extra usage" + "Configure Claude in Chrome": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Configure Claude in Chrome" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "속도 제한 초과 시 추가 사용량 구성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Chrome에서 Claude 설정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配置额外用量" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 Chrome 中配置 Claude" } } } }, - "Configure keybindings" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure keybindings" + "Configure extra usage": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Configure extra usage" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "키바인딩 구성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "속도 제한 초과 시 추가 사용량 구성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配置键位绑定" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置额外用量" } } } }, - "Configure remote environment" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure remote environment" + "Configure keybindings": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Configure keybindings" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "원격 환경 구성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "키바인딩 구성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配置远程环境" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置键位绑定" } } } }, - "Configure status line" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure status line" + "Configure remote environment": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Configure remote environment" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상태 표시줄 구성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "원격 환경 구성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配置状态行" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置远程环境" } } } }, - "Configure terminal keybindings" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure terminal keybindings" + "Configure status line": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Configure status line" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "터미널 키바인딩 구성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "상태 표시줄 구성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配置终端键位绑定" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置状态行" } } } }, - "Connect GitHub account to Claude Code on the web" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Connect GitHub account to Claude Code on the web" + "Configure terminal keybindings": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Configure terminal keybindings" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub 계정을 Claude Code 웹에 연결" + "ko": { + "stringUnit": { + "state": "translated", + "value": "터미널 키바인딩 구성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将 GitHub 账号连接到网页版 Claude Code" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "配置终端键位绑定" } } } }, - "context" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "context" + "Connect GitHub account to Claude Code on the web": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Connect GitHub account to Claude Code on the web" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "컨텍스트" + "ko": { + "stringUnit": { + "state": "translated", + "value": "GitHub 계정을 Claude Code 웹에 연결" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "上下文" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将 GitHub 账号连接到网页版 Claude Code" } } } }, - "Context window" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Context window" + "context": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "context" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "컨텍스트 윈도우" + "ko": { + "stringUnit": { + "state": "translated", + "value": "컨텍스트" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "上下文窗口" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "上下文" } } } }, - "Continue in Desktop app" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Continue in Desktop app" + "Context window": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Context window" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "데스크톱 앱에서 세션 계속" + "ko": { + "stringUnit": { + "state": "translated", + "value": "컨텍스트 윈도우" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在桌面应用中继续" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "上下文窗口" } } } }, - "Copied" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copied" + "Continue in Desktop app": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Continue in Desktop app" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "복사됨" + "ko": { + "stringUnit": { + "state": "translated", + "value": "데스크톱 앱에서 세션 계속" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已复制" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在桌面应用中继续" } } } }, - "Copy" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy" + "Copied": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Copied" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "복사" + "ko": { + "stringUnit": { + "state": "translated", + "value": "복사됨" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已复制" } } } }, - "Copy Conversation" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy Conversation" + "Copy": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Copy" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대화 복사" + "ko": { + "stringUnit": { + "state": "translated", + "value": "복사" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制对话" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制" } } } }, - "Copy last response to clipboard" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy last response to clipboard" + "Copy Conversation": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Copy Conversation" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "마지막 응답을 클립보드에 복사" + "ko": { + "stringUnit": { + "state": "translated", + "value": "대화 복사" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将最后一条响应复制到剪贴板" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制对话" } } } }, - "Copy Message" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy Message" + "Copy last response to clipboard": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Copy last response to clipboard" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지 복사" + "ko": { + "stringUnit": { + "state": "translated", + "value": "마지막 응답을 클립보드에 복사" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制消息" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将最后一条响应复制到剪贴板" } } } }, - "Copy output" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制输出" + "Copy output": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制输出" } } } }, - "Copy plan" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy plan" + "Copy plan": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Copy plan" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制计划" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "复制计划" } } } }, - "Cost" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Cost" + "Cost": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Cost" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "비용" + "ko": { + "stringUnit": { + "state": "translated", + "value": "비용" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "费用" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "费用" } } } }, - "Create a branch of current conversation" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Create a branch of current conversation" + "Create a branch of current conversation": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Create a branch of current conversation" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 대화의 브랜치 생성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "현재 대화의 브랜치 생성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "从当前对话创建分支" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "从当前对话创建分支" } } } }, - "Create new file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Create new file" + "Create new file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Create new file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 파일 생성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 파일 생성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "创建新文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "创建新文件" } } } }, - "Currently at %lld%%" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Currently at %lld%%" + "Currently at %lld%%": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Currently at %lld%%" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 %lld%%" + "ko": { + "stringUnit": { + "state": "translated", + "value": "현재 %lld%%" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "当前为 %lld%%" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "当前为 %lld%%" } } } }, - "Daily usage and session history visualization" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Daily usage and session history visualization" + "Daily usage and session history visualization": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Daily usage and session history visualization" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "일일 사용량, 세션 기록, 연속 기록 시각화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "일일 사용량, 세션 기록, 연속 기록 시각화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "每日用量和会话历史可视化" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "每日用量和会话历史可视化" } } } }, - "Decided" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Decided" + "Decided": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Decided" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已决定" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已决定" } } } }, - "Deep multi-agent cloud code review" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Deep multi-agent cloud code review" + "Deep multi-agent cloud code review": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Deep multi-agent cloud code review" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "다중 에이전트 심층 클라우드 코드 리뷰" + "ko": { + "stringUnit": { + "state": "translated", + "value": "다중 에이전트 심층 클라우드 코드 리뷰" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "深度多智能体云端代码评审" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "深度多智能体云端代码评审" } } } }, - "default" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "default" + "default": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "default" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본" + "ko": { + "stringUnit": { + "state": "translated", + "value": "기본" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "默认" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "默认" } } } }, - "Delete" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Delete" + "Delete": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Delete" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "삭제" + "ko": { + "stringUnit": { + "state": "translated", + "value": "삭제" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "删除" } } } }, - "Description" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Description" + "Description": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Description" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설명" + "ko": { + "stringUnit": { + "state": "translated", + "value": "설명" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "描述" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "描述" } } } }, - "description: short text shown in the command picker." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "description: short text shown in the command picker." + "description: short text shown in the command picker.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "description: short text shown in the command picker." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "description: 커맨드 선택기에 표시되는 짧은 설명입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "description: 커맨드 선택기에 표시되는 짧은 설명입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "description:显示在命令选择器中的简短文本。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "description:显示在命令选择器中的简短文本。" } } } }, - "Detail Description (optional)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Detail Description (optional)" + "Detail Description (optional)": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Detail Description (optional)" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상세 설명 (선택사항)" + "ko": { + "stringUnit": { + "state": "translated", + "value": "상세 설명 (선택사항)" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "详细描述(可选)" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "详细描述(可选)" } } } }, - "detailDescription: optional longer text shown in command details. Use null or omit it when empty." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "detailDescription: optional longer text shown in command details. Use null or omit it when empty." + "detailDescription: optional longer text shown in command details. Use null or omit it when empty.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "detailDescription: optional longer text shown in command details. Use null or omit it when empty." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "detailDescription: 커맨드 상세에 표시되는 선택적 긴 설명입니다. 비어 있으면 null을 쓰거나 생략하세요." + "ko": { + "stringUnit": { + "state": "translated", + "value": "detailDescription: 커맨드 상세에 표시되는 선택적 긴 설명입니다. 비어 있으면 null을 쓰거나 생략하세요." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "detailDescription:显示在命令详情中的可选长文本。为空时使用 null 或省略。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "detailDescription:显示在命令详情中的可选长文本。为空时使用 null 或省略。" } } } }, - "Diagnose installation/configuration" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Diagnose installation/configuration" + "Diagnose installation/configuration": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Diagnose installation/configuration" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치 및 설정 진단" + "ko": { + "stringUnit": { + "state": "translated", + "value": "설치 및 설정 진단" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "诊断安装/配置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "诊断安装/配置" } } } }, - "Diff" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Diff" + "Diff": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Diff" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Diff" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Diff" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "差异" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "差异" } } } }, - "Diff viewer for uncommitted changes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Diff viewer for uncommitted changes" + "Diff viewer for uncommitted changes": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Diff viewer for uncommitted changes" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "미커밋 변경사항 diff 뷰어" + "ko": { + "stringUnit": { + "state": "translated", + "value": "미커밋 변경사항 diff 뷰어" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未提交更改的差异查看器" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未提交更改的差异查看器" } } } }, - "Disable" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Disable" + "Disable": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Disable" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "비활성화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "비활성화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "停用" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "停用" } } } }, - "Draft a plan in an ultraplan session" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Draft a plan in an ultraplan session" + "Draft a plan in an ultraplan session": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Draft a plan in an ultraplan session" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ultraplan 세션에서 계획 작성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Ultraplan 세션에서 계획 작성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在 ultraplan 会话中起草计划" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在 ultraplan 会话中起草计划" } } } }, - "Drafting plan…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在起草计划…" + "Drafting plan…": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在起草计划…" } } } }, - "Duration" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Duration" + "Duration": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Duration" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "소요 시간" + "ko": { + "stringUnit": { + "state": "translated", + "value": "소요 시간" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "持续时间" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "持续时间" } } } }, - "Each custom command supports these properties:" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Each custom command supports these properties:" + "Each custom command supports these properties:": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Each custom command supports these properties:" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "각 커스텀 커맨드는 다음 속성을 지원합니다:" + "ko": { + "stringUnit": { + "state": "translated", + "value": "각 커스텀 커맨드는 다음 속성을 지원합니다:" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "每个自定义命令支持这些属性:" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "每个自定义命令支持这些属性:" } } } }, - "Each shortcut supports these properties:" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Each shortcut supports these properties:" + "Each shortcut supports these properties:": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Each shortcut supports these properties:" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "각 단축키는 다음 속성을 지원합니다:" + "ko": { + "stringUnit": { + "state": "translated", + "value": "각 단축키는 다음 속성을 지원합니다:" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "每个快捷方式支持这些属性:" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "每个快捷方式支持这些属性:" } } } }, - "Edit CLAUDE.md memory file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit CLAUDE.md memory file" + "Edit CLAUDE.md memory file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit CLAUDE.md memory file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "CLAUDE.md 메모리 파일 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "CLAUDE.md 메모리 파일 편집" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑 CLAUDE.md 记忆文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑 CLAUDE.md 记忆文件" } } } }, - "Edit Command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit Command" + "Edit Command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit Command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 편집" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑命令" } } } }, - "Edit file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit file" + "Edit file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "파일 편집" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑文件" } } } }, - "Edit Message" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit Message" + "Edit message...": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit message..." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "메시지 편집..." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑消息" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑消息..." } } } }, - "Edit message..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit message..." + "Edit multiple locations": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit multiple locations" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지 편집..." + "ko": { + "stringUnit": { + "state": "translated", + "value": "여러 위치 편집" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑消息..." + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑多个位置" } } } }, - "Edit multiple locations" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit multiple locations" + "Edit notebook": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit notebook" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "여러 위치 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "노트북 편집" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑多个位置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑笔记本" } } } }, - "Edit notebook" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit notebook" + "Edit Shortcut": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit Shortcut" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "노트북 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키 편집" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑笔记本" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑快捷方式" } } } }, - "Edit Shortcut" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit Shortcut" + "Edit the array below to add, remove, or change custom slash commands.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit the array below to add, remove, or change custom slash commands." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 편집" + "ko": { + "stringUnit": { + "state": "translated", + "value": "아래 배열을 편집해서 커스텀 슬래시 커맨드를 추가, 삭제, 변경하세요." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑下面的数组以添加、移除或更改自定义斜杠命令。" } } } }, - "Edit the array below to add, remove, or change custom slash commands." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit the array below to add, remove, or change custom slash commands." + "Edit the array below to add, remove, or change shortcuts.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Edit the array below to add, remove, or change shortcuts." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "아래 배열을 편집해서 커스텀 슬래시 커맨드를 추가, 삭제, 변경하세요." + "ko": { + "stringUnit": { + "state": "translated", + "value": "아래 배열을 편집해서 단축키를 추가, 삭제, 변경하세요." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑下面的数组以添加、移除或更改自定义斜杠命令。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑下面的数组以添加、移除或更改快捷方式。" } } } }, - "Edit the array below to add, remove, or change shortcuts." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit the array below to add, remove, or change shortcuts." + "Enable": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Enable" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "아래 배열을 편집해서 단축키를 추가, 삭제, 변경하세요." + "ko": { + "stringUnit": { + "state": "translated", + "value": "활성화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑下面的数组以添加、移除或更改快捷方式。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "启用" } } } }, - "Enable" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Enable" + "Enable debug logging and diagnose issues": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Enable debug logging and diagnose issues" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "활성화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "디버그 로그 활성화 및 문제 진단" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "启用调试日志并诊断问题" } } } }, - "Enable debug logging and diagnose issues" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Enable debug logging and diagnose issues" + "Enter plan mode": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Enter plan mode" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "디버그 로그 활성화 및 문제 진단" + "ko": { + "stringUnit": { + "state": "translated", + "value": "플랜 모드 진입" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用调试日志并诊断问题" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "进入计划模式" } } } }, - "Enter plan mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Enter plan mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "플랜 모드 진입" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "进入计划模式" + "error": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "error" } } } }, - "error" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "error" - } - } - } - }, - "Error occurred" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Error occurred" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "오류 발생" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "发生错误" - } - } - } - }, - "Execution Mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Execution Mode" + "Error occurred": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Error occurred" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "실행 모드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "오류 발생" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "执行模式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发生错误" } } } }, - "Exit CLI" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Exit CLI" + "Execution Mode": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Execution Mode" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "CLI 종료" + "ko": { + "stringUnit": { + "state": "translated", + "value": "실행 모드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "退出 CLI" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "执行模式" } } } }, - "Export" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Export" + "Exit CLI": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Exit CLI" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "내보내기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "CLI 종료" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导出" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "退出 CLI" } } } }, - "Export conversation as text" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Export conversation as text" + "Export": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Export" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 대화를 텍스트로 내보내기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "내보내기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将对话导出为文本" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导出" } } } }, - "Export custom commands to a JSON file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Export custom commands to a JSON file" + "Export conversation as text": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Export conversation as text" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커스텀 커맨드를 JSON 파일로 내보냅니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "현재 대화를 텍스트로 내보내기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将自定义命令导出为 JSON 文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将对话导出为文本" } } } }, - "Export Shortcuts" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Export Shortcuts" + "Export custom commands to a JSON file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Export custom commands to a JSON file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 내보내기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커스텀 커맨드를 JSON 파일로 내보냅니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导出快捷按钮" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将自定义命令导出为 JSON 文件" } } } }, - "Export shortcuts to a JSON file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Export shortcuts to a JSON file" + "Export Shortcuts": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Export Shortcuts" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키를 JSON 파일로 내보냅니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키 내보내기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将快捷方式导出为 JSON 文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导出快捷按钮" } } } }, - "Export Slash Commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Export Slash Commands" + "Export shortcuts to a JSON file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Export shortcuts to a JSON file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드 내보내기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키를 JSON 파일로 내보냅니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导出斜杠命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将快捷方式导出为 JSON 文件" } } } }, - "File Search" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File Search" + "Export Slash Commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Export Slash Commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 검색" + "ko": { + "stringUnit": { + "state": "translated", + "value": "슬래시 커맨드 내보내기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件搜索" - } - } - } - }, - "Files" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导出斜杠命令" } } } }, - "Find files" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Find files" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 찾기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查找文件" + "Files": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "文件" } } } }, - "Generate a one-line session summary" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Generate a one-line session summary" + "Find files": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Find files" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "세션 한 줄 요약 생성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "파일 찾기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "生成单行会话摘要" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查找文件" } } } }, - "Generate a team onboarding guide" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Generate a team onboarding guide" + "Generate a one-line session summary": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Generate a one-line session summary" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "팀 온보딩 가이드 생성" + "ko": { + "stringUnit": { + "state": "translated", + "value": "세션 한 줄 요약 생성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "生成团队入门指南" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "生成单行会话摘要" } } } }, - "Generating response..." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Generating response..." + "Generate a team onboarding guide": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Generate a team onboarding guide" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "응답 생성 중..." + "ko": { + "stringUnit": { + "state": "translated", + "value": "팀 온보딩 가이드 생성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在生成响应..." + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "生成团队入门指南" } } } }, - "How can I help you?" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "How can I help you?" + "How can I help you?": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "How can I help you?" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "무엇을 도와드릴까요?" + "ko": { + "stringUnit": { + "state": "translated", + "value": "무엇을 도와드릴까요?" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "有什么可以帮你?" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "有什么可以帮你?" } } } }, - "id: optional unique identifier (UUID). Auto-generated on import if omitted." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "id: optional unique identifier (UUID). Auto-generated on import if omitted." + "id: optional unique identifier (UUID). Auto-generated on import if omitted.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "id: optional unique identifier (UUID). Auto-generated on import if omitted." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "id: 선택적 고유 식별자 (UUID). 가져올 때 생략하면 자동 생성됩니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "id: 선택적 고유 식별자 (UUID). 가져올 때 생략하면 자동 생성됩니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "id:可选的唯一标识符(UUID)。导入时省略则自动生成。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "id:可选的唯一标识符(UUID)。导入时省略则自动生成。" } } } }, - "Image not available" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "图像不可用" + "Image not available": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "图像不可用" } } } }, - "Image unavailable" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "图像不可用" + "Image unavailable": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "图像不可用" } } } }, - "Import" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import" + "Import": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "가져오기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "가져오기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导入" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入" } } } }, - "Import commands from a JSON file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import commands from a JSON file" + "Import commands from a JSON file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import commands from a JSON file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "JSON 파일에서 커맨드를 가져옵니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "JSON 파일에서 커맨드를 가져옵니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "从 JSON 文件导入命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "从 JSON 文件导入命令" } } } }, - "Import Failed" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import Failed" + "Import Failed": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import Failed" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "가져오기 실패" + "ko": { + "stringUnit": { + "state": "translated", + "value": "가져오기 실패" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导入失败" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入失败" } } } }, - "Import Shortcuts" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import Shortcuts" + "Import Shortcuts": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import Shortcuts" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 가져오기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키 가져오기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导入快捷按钮" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入快捷按钮" } } } }, - "Import shortcuts from a JSON file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import shortcuts from a JSON file" + "Import shortcuts from a JSON file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import shortcuts from a JSON file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "JSON 파일에서 단축키를 가져옵니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "JSON 파일에서 단축키를 가져옵니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "从 JSON 文件导入快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "从 JSON 文件导入快捷方式" } } } }, - "Import Slash Commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import Slash Commands" + "Import Slash Commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import Slash Commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드 가져오기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "슬래시 커맨드 가져오기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导入斜杠命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入斜杠命令" } } } }, - "Import Succeeded" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Import Succeeded" + "Import Succeeded": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Import Succeeded" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "가져오기 성공" + "ko": { + "stringUnit": { + "state": "translated", + "value": "가져오기 성공" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "导入成功" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "导入成功" } } } }, - "Imported %lld custom commands." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Imported %lld custom commands." + "Imported %lld custom commands.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Imported %lld custom commands." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld개 커스텀 커맨드를 가져왔습니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "%lld개 커스텀 커맨드를 가져왔습니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已导入 %lld 个自定义命令。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已导入 %lld 个自定义命令。" } } } }, - "Initialize project with CLAUDE.md" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Initialize project with CLAUDE.md" + "Initialize project with CLAUDE.md": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Initialize project with CLAUDE.md" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "CLAUDE.md로 프로젝트 초기화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "CLAUDE.md로 프로젝트 초기화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "使用 CLAUDE.md 初始化项目" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "使用 CLAUDE.md 初始化项目" } } } }, - "Input tokens" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Input tokens" + "Input tokens": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Input tokens" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력 토큰" + "ko": { + "stringUnit": { + "state": "translated", + "value": "입력 토큰" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输入 token" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "输入 token" } } } }, - "Install Slack app" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Install Slack app" + "Install Slack app": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Install Slack app" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Slack 앱 설치" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Slack 앱 설치" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "安装 Slack 应用" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "安装 Slack 应用" } } } }, - "Interactive (Terminal)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interactive (Terminal)" + "Interactive (Terminal)": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Interactive (Terminal)" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인터랙티브 (터미널)" + "ko": { + "stringUnit": { + "state": "translated", + "value": "인터랙티브 (터미널)" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "交互式(终端)" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "交互式(终端)" } } } }, - "Interactive feature lessons with demos" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interactive feature lessons with demos" + "Interactive feature lessons with demos": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Interactive feature lessons with demos" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "애니메이션 데모와 함께하는 기능 학습" + "ko": { + "stringUnit": { + "state": "translated", + "value": "애니메이션 데모와 함께하는 기능 학습" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "带演示的交互式功能课程" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "带演示的交互式功能课程" } } } }, - "Interactive terminal" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interactive terminal" + "Interactive terminal": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Interactive terminal" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인터랙티브 터미널" + "ko": { + "stringUnit": { + "state": "translated", + "value": "인터랙티브 터미널" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "交互式终端" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "交互式终端" } } } }, - "Interrupted" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interrupted" + "Interrupted": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Interrupted" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "중단됨" + "ko": { + "stringUnit": { + "state": "translated", + "value": "중단됨" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已中断" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "已中断" } } } }, - "Invalid JSON format." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Invalid JSON format." + "Invalid JSON format.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Invalid JSON format." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "유효하지 않은 JSON 형식입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "유효하지 않은 JSON 형식입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "JSON 格式无效。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "JSON 格式无效。" } } } }, - "isInteractive: true runs the command in the interactive terminal." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "isInteractive: true runs the command in the interactive terminal." + "isInteractive: true runs the command in the interactive terminal.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "isInteractive: true runs the command in the interactive terminal." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "isInteractive: true이면 인터랙티브 터미널에서 실행됩니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "isInteractive: true이면 인터랙티브 터미널에서 실행됩니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "isInteractive:设为 true 后,命令会在交互式终端中运行。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "isInteractive:设为 true 后,命令会在交互式终端中运行。" } } } }, - "isTerminalCommand: true runs the message as a terminal command instead of sending it to chat." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "isTerminalCommand: true runs the message as a terminal command instead of sending it to chat." + "isTerminalCommand: true runs the message as a terminal command instead of sending it to chat.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "isTerminalCommand: true runs the message as a terminal command instead of sending it to chat." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "isTerminalCommand: true이면 채팅 대신 터미널 커맨드로 실행됩니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "isTerminalCommand: true이면 채팅 대신 터미널 커맨드로 실행됩니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "isTerminalCommand:设为 true 后,会把消息作为终端命令运行,而不是发送到聊天。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "isTerminalCommand:设为 true 后,会把消息作为终端命令运行,而不是发送到聊天。" } } } }, - "json" : { - - }, - "List available skills" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "List available skills" + "json": {}, + "List available skills": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "List available skills" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사용 가능한 스킬 목록" + "ko": { + "stringUnit": { + "state": "translated", + "value": "사용 가능한 스킬 목록" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "列出可用技能" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "列出可用技能" } } } }, - "Load Claude API reference for current project" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Load Claude API reference for current project" + "Load Claude API reference for current project": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Load Claude API reference for current project" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 프로젝트용 Claude API 레퍼런스 로드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "현재 프로젝트용 Claude API 레퍼런스 로드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "为当前项目加载 Claude API 参考" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "为当前项目加载 Claude API 参考" } } } }, - "loading..." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "loading..." + "Log in to Anthropic account": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Log in to Anthropic account" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "불러오는 중..." + "ko": { + "stringUnit": { + "state": "translated", + "value": "Anthropic 계정 로그인" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载..." + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "登录 Anthropic 账号" } } } }, - "Log in to Anthropic account" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Log in to Anthropic account" + "Log out of Anthropic account": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Log out of Anthropic account" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Anthropic 계정 로그인" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Anthropic 계정 로그아웃" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "登录 Anthropic 账号" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "退出 Anthropic 账号" } } } }, - "Log out of Anthropic account" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Log out of Anthropic account" + "Manage agent configuration": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage agent configuration" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Anthropic 계정 로그아웃" + "ko": { + "stringUnit": { + "state": "translated", + "value": "에이전트 구성 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "退出 Anthropic 账号" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理智能体配置" } } } }, - "Manage agent configuration" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage agent configuration" + "Manage background tasks": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage background tasks" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "에이전트 구성 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "백그라운드 작업 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理智能体配置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理后台任务" } } } }, - "Manage background tasks" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage background tasks" + "Manage cloud scheduled tasks": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage cloud scheduled tasks" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "백그라운드 작업 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "클라우드 예약 작업 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理后台任务" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理云端计划任务" } } } }, - "Manage cloud scheduled tasks" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage cloud scheduled tasks" + "Manage Commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage Commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "클라우드 예약 작업 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理云端计划任务" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理命令" } } } }, - "Manage Commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage Commands" + "Manage IDE integration": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage IDE integration" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "IDE 통합 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理 IDE 集成" } } } }, - "Manage IDE integration" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage IDE integration" + "Manage MCP servers": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage MCP servers" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "IDE 통합 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "MCP 서버 연결 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理 IDE 集成" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理 MCP 服务器" } } } }, - "Manage MCP servers" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage MCP servers" + "Manage permissions": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage permissions" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "MCP 서버 연결 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "권한 규칙 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理 MCP 服务器" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理权限" } } } }, - "Manage permissions" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage permissions" + "Manage plugins": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Manage plugins" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 규칙 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "플러그인 관리" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理权限" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "管理插件" } } } }, - "Manage plugins" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage plugins" + "Message": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Message" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "플러그인 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "메시지" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理插件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "消息" } } } }, - "Manage shortcuts" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage shortcuts" + "Message sent to Claude or command run in terminal": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Message sent to Claude or command run in terminal" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 관리" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Claude에 전송할 메시지 또는 터미널에서 실행할 커맨드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理快捷按钮" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发送给 Claude 的消息或在终端中运行的命令" } } } }, - "Message" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Message" + "message: text sent to Claude, or command run in the terminal.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "message: text sent to Claude, or command run in the terminal." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지" + "ko": { + "stringUnit": { + "state": "translated", + "value": "message: Claude에 전송할 텍스트 또는 터미널에서 실행할 커맨드입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "消息" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "message:发送给 Claude 的文本,或在终端中运行的命令。" } } } }, - "Message sent to Claude or command run in terminal" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Message sent to Claude or command run in terminal" + "Mobile app QR code": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Mobile app QR code" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude에 전송할 메시지 또는 터미널에서 실행할 커맨드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "모바일 앱 QR 코드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "发送给 Claude 的消息或在终端中运行的命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "移动应用二维码" } } } }, - "message: text sent to Claude, or command run in the terminal." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "message: text sent to Claude, or command run in the terminal." + "Name": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Name" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "message: Claude에 전송할 텍스트 또는 터미널에서 실행할 커맨드입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "이름" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "message:发送给 Claude 的文本,或在终端中运行的命令。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "名称" } } } }, - "Mobile app QR code" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Mobile app QR code" + "Name shown on the button": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Name shown on the button" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모바일 앱 QR 코드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "버튼에 표시될 이름" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "移动应用二维码" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "按钮上显示的名称" } } } }, - "Name" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Name" + "name: command name without the leading slash.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "name: command name without the leading slash." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이름" + "ko": { + "stringUnit": { + "state": "translated", + "value": "name: 앞의 /를 제외한 커맨드 이름입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "名称" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "name:不含开头斜杠的命令名称。" } } } }, - "Name shown on the button" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Name shown on the button" + "name: label shown on the shortcut button.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "name: label shown on the shortcut button." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "버튼에 표시될 이름" + "ko": { + "stringUnit": { + "state": "translated", + "value": "name: 단축키 버튼에 표시되는 이름입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "按钮上显示的名称" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "name:显示在快捷方式按钮上的标签。" } } } }, - "name: command name without the leading slash." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "name: command name without the leading slash." + "New Command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "New Command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "name: 앞의 /를 제외한 커맨드 이름입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 커맨드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "name:不含开头斜杠的命令名称。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新建命令" } } } }, - "name: label shown on the shortcut button." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "name: label shown on the shortcut button." + "New Shortcut": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "New Shortcut" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "name: 단축키 버튼에 표시되는 이름입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 단축키" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "name:显示在快捷方式按钮上的标签。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "新建快捷方式" } } } }, - "New Command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "New Command" + "No changes": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "No changes" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 커맨드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "변경사항 없음" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "新建命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有变更" } } } }, - "New Shortcut" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "New Shortcut" + "No results found": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "No results found" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 단축키" + "ko": { + "stringUnit": { + "state": "translated", + "value": "검색 결과 없음" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "新建快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "未找到结果" } } } }, - "No changes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No changes" + "No shortcuts": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "No shortcuts" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "변경사항 없음" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키 없음" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有变更" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有快捷方式" } } } }, - "No results found" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No results found" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "검색 결과 없음" + "No todos": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "No todos" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未找到结果" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "没有待办" } } } }, - "No shortcuts" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有快捷方式" + "ok": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "ok" } } } }, - "No todos" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No todos" + "OK": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "OK" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有待办" - } - } - } - }, - "ok" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "ok" - } - } - } - }, - "OK" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "OK" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "확인" + "ko": { + "stringUnit": { + "state": "translated", + "value": "확인" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "确定" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "确定" } } } }, - "Open in browser" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Open in browser" + "Open in browser": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Open in browser" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "브라우저에서 열기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "브라우저에서 열기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在浏览器中打开" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在浏览器中打开" } } } }, - "Open the plan to accept or reject" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开计划以接受或拒绝" + "Open the plan to accept or reject": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开计划以接受或拒绝" } } } }, - "Open the plan to review the decision" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开计划以查看决策" + "Open the plan to review the decision": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "打开计划以查看决策" } } } }, - "Optional longer description shown in command details" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Optional longer description shown in command details" + "Optional longer description shown in command details": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Optional longer description shown in command details" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 상세에 표시되는 선택적 긴 설명" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 상세에 표시되는 선택적 긴 설명" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示在命令详情中的可选长描述" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示在命令详情中的可选长描述" } } } }, - "Orchestrate large-scale parallel changes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Orchestrate large-scale parallel changes" + "Orchestrate large-scale parallel changes": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Orchestrate large-scale parallel changes" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대규모 병렬 변경 오케스트레이션" + "ko": { + "stringUnit": { + "state": "translated", + "value": "대규모 병렬 변경 오케스트레이션" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编排大规模并行更改" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编排大规模并行更改" } } } }, - "Order Claude Code stickers" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Order Claude Code stickers" + "Order Claude Code stickers": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Order Claude Code stickers" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude Code 스티커 주문" + "ko": { + "stringUnit": { + "state": "translated", + "value": "Claude Code 스티커 주문" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "订购 Claude Code 贴纸" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "订购 Claude Code 贴纸" } } } }, - "Output tokens" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Output tokens" + "Output tokens": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Output tokens" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "출력 토큰" + "ko": { + "stringUnit": { + "state": "translated", + "value": "출력 토큰" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输出 token" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "输出 token" } } } }, - "Plan" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan" + "Plan": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Plan" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "계획" + "ko": { + "stringUnit": { + "state": "translated", + "value": "계획" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "计划" } } } }, - "Plan content unavailable." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan content unavailable." + "Plan content unavailable.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Plan content unavailable." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划内容不可用。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "计划内容不可用。" } } } }, - "Plan is still drafting…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划仍在起草…" + "Plan is still drafting…": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "计划仍在起草…" } } } }, - "Plan mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan mode" + "Plan mode": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Plan mode" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划模式" - } - } - } - }, - "Plan mode is on — Add menu" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划模式已开启 — 添加菜单" - } - } - } - }, - "Plan ready" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划已就绪" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "计划模式" } } } }, - "Plan usage limits and rate limits" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan usage limits and rate limits" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "요금제 사용 한도 및 속도 제한" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "规划用量限制和速率限制" + "Plan mode is on — Add menu": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "计划模式已开启 — 添加菜单" } } } }, - "Portion of the current conversation's context window in use. When it fills, older messages may be summarized or dropped." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Portion of the current conversation's context window in use. When it fills, older messages may be summarized or dropped." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 대화의 컨텍스트 윈도우 중 사용 중인 비율입니다. 가득 차면 이전 메시지가 요약되거나 삭제될 수 있습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "当前对话上下文窗口的已用比例。填满后,较早消息可能会被总结或丢弃。" + "Plan ready": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "计划已就绪" } } } }, - "Preview" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Preview" + "Plan usage limits and rate limits": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Plan usage limits and rate limits" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "미리보기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "요금제 사용 한도 및 속도 제한" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "预览" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "规划用量限制和速率限制" } } } }, - "Privacy settings (Pro/Max)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Privacy settings (Pro/Max)" + "Portion of the current conversation's context window in use. When it fills, older messages may be summarized or dropped.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Portion of the current conversation's context window in use. When it fills, older messages may be summarized or dropped." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "개인정보 설정 (Pro/Max)" + "ko": { + "stringUnit": { + "state": "translated", + "value": "현재 대화의 컨텍스트 윈도우 중 사용 중인 비율입니다. 가득 차면 이전 메시지가 요약되거나 삭제될 수 있습니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "隐私设置(Pro/Max)" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "当前对话上下文窗口的已用比例。填满后,较早消息可能会被总结或丢弃。" } } } }, - "Pull a web session into this terminal" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Pull a web session into this terminal" + "Privacy settings (Pro/Max)": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Privacy settings (Pro/Max)" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "웹 세션을 터미널로 가져오기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "개인정보 설정 (Pro/Max)" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将网页会话拉取到此终端" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "隐私设置(Pro/Max)" } } } }, - "Question" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Question" + "Pull a web session into this terminal": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Pull a web session into this terminal" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "질문" + "ko": { + "stringUnit": { + "state": "translated", + "value": "웹 세션을 터미널로 가져오기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "问题" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将网页会话拉取到此终端" } } } }, - "Read file" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Read file" + "Read file": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Read file" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 읽기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "파일 읽기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "读取文件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "读取文件" } } } }, - "Reduce permission prompts by scanning transcripts" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reduce permission prompts by scanning transcripts" + "Reduce permission prompts by scanning transcripts": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reduce permission prompts by scanning transcripts" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대화 기록 분석으로 권한 요청 횟수 줄이기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "대화 기록 분석으로 권한 요청 횟수 줄이기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "通过扫描转录记录减少权限提示" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "通过扫描转录记录减少权限提示" } } } }, - "Register frequently used messages as shortcuts" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Register frequently used messages as shortcuts" + "Register frequently used messages as shortcuts": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Register frequently used messages as shortcuts" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "자주 사용하는 메시지를 단축키로 등록하세요" + "ko": { + "stringUnit": { + "state": "translated", + "value": "자주 사용하는 메시지를 단축키로 등록하세요" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将常用消息注册为快捷方式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将常用消息注册为快捷方式" } } } }, - "Reject" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reject" + "Reject": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reject" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "拒绝" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "拒绝" } } } }, - "Reject with Reason" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reject with Reason" + "Reject with Reason": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reject with Reason" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "拒绝并说明原因" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "拒绝并说明原因" } } } }, - "Reload plugins" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reload plugins" + "Reload plugins": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reload plugins" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "플러그인 다시 로드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "플러그인 다시 로드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "重新加载插件" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重新加载插件" } } } }, - "Remote control from claude.ai" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Remote control from claude.ai" + "Remote control from claude.ai": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Remote control from claude.ai" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "claude.ai에서 원격 제어" + "ko": { + "stringUnit": { + "state": "translated", + "value": "claude.ai에서 원격 제어" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "来自 claude.ai 的远程控制" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "来自 claude.ai 的远程控制" } } } }, - "Remove" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "移除" + "Remove": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "移除" } } } }, - "Rename session" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Rename session" + "Rename session": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Rename session" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "세션 이름 변경" + "ko": { + "stringUnit": { + "state": "translated", + "value": "세션 이름 변경" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "重命名会话" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重命名会话" } } } }, - "Repeat execution (e.g. /loop 5m /foo)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Repeat execution (e.g. /loop 5m /foo)" + "Repeat execution (e.g. /loop 5m /foo)": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Repeat execution (e.g. /loop 5m /foo)" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "반복 실행 (예: /loop 5m /foo)" + "ko": { + "stringUnit": { + "state": "translated", + "value": "반복 실행 (예: /loop 5m /foo)" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "重复执行(例如 /loop 5m /foo)" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重复执行(例如 /loop 5m /foo)" } } } }, - "Reset" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reset" + "Reset": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reset" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "초기화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "초기화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "重置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重置" } } } }, - "Reset Default Commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reset Default Commands" + "Reset Default Commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reset Default Commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 커맨드 초기화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "기본 커맨드 초기화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "重置默认命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重置默认命令" } } } }, - "Reset Defaults" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reset Defaults" + "Reset Defaults": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Reset Defaults" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본값 초기화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "기본값 초기화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "重置默认值" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "重置默认值" } } } }, - "Resets in %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Resets in %@" + "Resets in %@": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Resets in %@" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ 후 리셋" + "ko": { + "stringUnit": { + "state": "translated", + "value": "%@ 후 리셋" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ 后重置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "%@ 后重置" } } } }, - "Response in progress" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "响应进行中" + "Response in progress": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "响应进行中" } } } }, - "Restore Default" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Restore Default" + "Restore Default": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Restore Default" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본값 복원" + "ko": { + "stringUnit": { + "state": "translated", + "value": "기본값 복원" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "恢复默认" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "恢复默认" } } } }, - "Restore modified default commands to their original state" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Restore modified default commands to their original state" + "Restore modified default commands to their original state": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Restore modified default commands to their original state" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "수정한 기본 커맨드를 원래 상태로 복원합니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "수정한 기본 커맨드를 원래 상태로 복원합니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将修改过的默认命令恢复到原始状态" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "将修改过的默认命令恢复到原始状态" } } } }, - "Review" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查看" + "Review": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看" } } } }, - "Review a pull request locally" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Review a pull request locally" + "Review a pull request locally": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Review a pull request locally" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "로컬에서 PR 리뷰" + "ko": { + "stringUnit": { + "state": "translated", + "value": "로컬에서 PR 리뷰" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在本地评审拉取请求" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在本地评审拉取请求" } } } }, - "Review and fix code quality/efficiency of changes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Review and fix code quality/efficiency of changes" + "Review and fix code quality/efficiency of changes": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Review and fix code quality/efficiency of changes" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "변경사항 코드 품질/효율성 검토 및 수정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "변경사항 코드 품질/효율성 검토 및 수정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "评审并修复更改的代码质量/效率问题" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "评审并修复更改的代码质量/效率问题" } } } }, - "Rewind to a previous point" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Rewind to a previous point" + "Rewind to a previous point": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Rewind to a previous point" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이전 시점으로 되돌리기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "이전 시점으로 되돌리기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "回退到之前的位置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "回退到之前的位置" } } } }, - "Run as terminal command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Run as terminal command" + "Run as terminal command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Run as terminal command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "터미널 커맨드로 실행" + "ko": { + "stringUnit": { + "state": "translated", + "value": "터미널 커맨드로 실행" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "作为终端命令运行" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "作为终端命令运行" } } } }, - "Run command" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Run command" + "Run command": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Run command" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 실행" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 실행" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "运行命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "运行命令" } } } }, - "Running" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Running" + "Running": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Running" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "실행 중" + "ko": { + "stringUnit": { + "state": "translated", + "value": "실행 중" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在运行" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "正在运行" } } } }, - "RxCode shortcut export file." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "RxCode shortcut export file." + "RxCode shortcut export file.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "RxCode shortcut export file." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode 단축키 내보내기 파일입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "RxCode 단축키 내보내기 파일입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode 快捷方式导出文件。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "RxCode 快捷方式导出文件。" } } } }, - "RxCode slash command export file." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "RxCode slash command export file." + "RxCode slash command export file.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "RxCode slash command export file." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode 슬래시 커맨드 내보내기 파일입니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "RxCode 슬래시 커맨드 내보내기 파일입니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode 斜杠命令导出文件。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "RxCode 斜杠命令导出文件。" } } } }, - "Save" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Save" + "Save": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Save" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "저장" + "ko": { + "stringUnit": { + "state": "translated", + "value": "저장" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "保存" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "保存" } } } }, - "Search commands..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Search commands..." + "Search commands...": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Search commands..." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 검색..." + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 검색..." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "搜索命令..." + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "搜索命令..." } } } }, - "Search in code" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Search in code" + "Search in code": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Search in code" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "코드 검색" + "ko": { + "stringUnit": { + "state": "translated", + "value": "코드 검색" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在代码中搜索" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在代码中搜索" } } } }, - "Select/change AI model" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Select/change AI model" + "Select/change AI model": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Select/change AI model" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "AI 모델 선택/변경" + "ko": { + "stringUnit": { + "state": "translated", + "value": "AI 모델 선택/변경" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "选择/更改 AI 模型" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "选择/更改 AI 模型" } } } }, - "Send" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Send" + "Send": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Send" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "전송" + "ko": { + "stringUnit": { + "state": "translated", + "value": "전송" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "发送" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发送" } } } }, - "Send all as one" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "合并发送" + "Send all as one": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "合并发送" } } } }, - "Send feedback" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Send feedback" + "Send feedback": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Send feedback" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "发送反馈" - } - } - } - }, - "Send now — cancels current response" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "立即发送 — 取消当前响应" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "发送反馈" } } } }, - "Session analysis report" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Session analysis report" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "세션 분석 보고서 생성" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "会话分析报告" + "Send now — cancels current response": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "立即发送 — 取消当前响应" } } } }, - "Session Usage" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Session Usage" + "Session analysis report": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Session analysis report" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "세션 사용량" + "ko": { + "stringUnit": { + "state": "translated", + "value": "세션 분석 보고서 생성" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "会话用量" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "会话分析报告" } } } }, - "Set model effort level" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Set model effort level" + "Session Usage": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Session Usage" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모델 effort 수준 설정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "세션 사용량" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设置模型推理强度" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "会话用量" } } } }, - "Set prompt bar color" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Set prompt bar color" + "Set model effort level": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Set model effort level" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프롬프트 바 색상 설정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "모델 effort 수준 설정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设置提示栏颜色" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设置模型推理强度" } } } }, - "Set terminal UI renderer" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Set terminal UI renderer" + "Set prompt bar color": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Set prompt bar color" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "터미널 UI 렌더러 설정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "프롬프트 바 색상 설정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设置终端 UI 渲染器" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设置提示栏颜色" } } } }, - "Set up GitHub Actions app" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Set up GitHub Actions app" + "Set terminal UI renderer": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Set terminal UI renderer" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub Actions 앱 설정" + "ko": { + "stringUnit": { + "state": "translated", + "value": "터미널 UI 렌더러 설정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设置 GitHub Actions 应用" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设置终端 UI 渲染器" } } } }, - "Settings interface" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Settings interface" + "Set up GitHub Actions app": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Set up GitHub Actions app" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설정 인터페이스" + "ko": { + "stringUnit": { + "state": "translated", + "value": "GitHub Actions 앱 설정" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设置界面" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设置 GitHub Actions 应用" } } } }, - "Share free 1-week passes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Share free 1-week passes" + "Settings interface": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Settings interface" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "1주 무료 이용권 공유" + "ko": { + "stringUnit": { + "state": "translated", + "value": "설정 인터페이스" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "分享免费 1 周通行证" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "设置界面" } } } }, - "Short description" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Short description" + "Share free 1-week passes": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Share free 1-week passes" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "짧은 설명" + "ko": { + "stringUnit": { + "state": "translated", + "value": "1주 무료 이용권 공유" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "简短描述" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "分享免费 1 周通行证" } } } }, - "Short description shown in the command picker" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Short description shown in the command picker" + "Short description": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Short description" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 선택기에 표시되는 짧은 설명" + "ko": { + "stringUnit": { + "state": "translated", + "value": "짧은 설명" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示在命令选择器中的简短描述" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "简短描述" } } } }, - "Shortcut" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Shortcut" + "Short description shown in the command picker": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Short description shown in the command picker" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키" + "ko": { + "stringUnit": { + "state": "translated", + "value": "커맨드 선택기에 표시되는 짧은 설명" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "快捷按钮" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示在命令选择器中的简短描述" } } } }, - "Shortcut button label" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Shortcut button label" + "Shortcut button label": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Shortcut button label" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 버튼 이름" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키 버튼 이름" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "快捷方式按钮标签" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "快捷方式按钮标签" } } } }, - "Shortcut Manager" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Shortcut Manager" + "Shortcut Manager": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Shortcut Manager" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 관리자" + "ko": { + "stringUnit": { + "state": "translated", + "value": "단축키 관리자" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "快捷方式管理器" - } - } - } - }, - "Shortcuts" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "快捷按钮" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "快捷方式管理器" } } } }, - "Show %lld earlier messages" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Show %lld earlier messages" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld개 이전 메시지 보기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示前 %lld 条消息" + "Shortcuts": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "快捷按钮" } } } }, - "Show help" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Show help" + "Show help": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Show help" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "도움말 보기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "도움말 보기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示帮助" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示帮助" } } } }, - "Show less" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Show less" + "Show less": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Show less" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "접기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "접기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "收起" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "收起" } } } }, - "Show more" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Show more" + "Show more": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Show more" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "더 보기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "더 보기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示更多" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "显示更多" } } } }, - "Side question not added to conversation" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Side question not added to conversation" + "Side question not added to conversation": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Side question not added to conversation" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대화에 추가되지 않는 부가 질문" + "ko": { + "stringUnit": { + "state": "translated", + "value": "대화에 추가되지 않는 부가 질문" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "旁路问题未添加到对话" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "旁路问题未添加到对话" } } } }, - "Skill" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skill" + "Skill": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Skill" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "스킬" + "ko": { + "stringUnit": { + "state": "translated", + "value": "스킬" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "技能" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "技能" } } } }, - "Slash Command Manager" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Slash Command Manager" + "Slash Command Manager": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Slash Command Manager" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드 관리자" + "ko": { + "stringUnit": { + "state": "translated", + "value": "슬래시 커맨드 관리자" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "斜杠命令管理器" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "斜杠命令管理器" } } } }, - "Slash Commands" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Slash Commands" + "Slash Commands": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Slash Commands" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "슬래시 커맨드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "斜杠命令" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "斜杠命令" } } } }, - "Start a new conversation" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Start a new conversation" + "Start a new conversation": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Start a new conversation" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 대화 시작" + "ko": { + "stringUnit": { + "state": "translated", + "value": "새 대화 시작" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "开始新对话" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "开始新对话" } } } }, - "Start in plan mode" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "以计划模式开始" + "Start in plan mode": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "以计划模式开始" } } } }, - "Subagent" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Subagent" + "Subagent": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Subagent" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "서브에이전트" + "ko": { + "stringUnit": { + "state": "translated", + "value": "서브에이전트" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "子智能体" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "子智能体" } } } }, - "Submit feedback/bug report" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Submit feedback/bug report" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "피드백/버그 보고" + "Submit feedback/bug report": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Submit feedback/bug report" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "提交反馈/错误报告" - } - } - } - }, - "Tell Claude what to change" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Tell Claude what to change" + "ko": { + "stringUnit": { + "state": "translated", + "value": "피드백/버그 보고" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "告诉 Claude 需要修改什么" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "提交反馈/错误报告" } } } }, - "terminal" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "terminal" + "Switch to horizontal scroll": {}, + "Switch to wrap": {}, + "Tell Claude what to change": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Tell Claude what to change" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "터미널" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "终端" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "告诉 Claude 需要修改什么" } } } }, - "The leading slash is optional while editing names; RxCode saves names without it." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "The leading slash is optional while editing names; RxCode saves names without it." + "terminal": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "terminal" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이름을 편집할 때 앞의 /는 선택사항입니다. RxCode는 / 없이 저장합니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "터미널" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑名称时开头的斜杠可选;RxCode 保存时不包含它。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "终端" } } } }, - "Thinking..." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Thinking..." + "The leading slash is optional while editing names; RxCode saves names without it.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "The leading slash is optional while editing names; RxCode saves names without it." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "생각하는 중..." + "ko": { + "stringUnit": { + "state": "translated", + "value": "이름을 편집할 때 앞의 /는 선택사항입니다. RxCode는 / 없이 저장합니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在思考..." + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "编辑名称时开头的斜杠可选;RxCode 保存时不包含它。" } } } }, - "This command will run in the terminal when the button is clicked" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "This command will run in the terminal when the button is clicked" + "This command will run in the terminal when the button is clicked": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "This command will run in the terminal when the button is clicked" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "버튼을 클릭하면 이 커맨드가 터미널에서 실행됩니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "버튼을 클릭하면 이 커맨드가 터미널에서 실행됩니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "点击按钮时,此命令会在终端中运行" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "点击按钮时,此命令会在终端中运行" } } } }, - "This message will be sent when the button is clicked" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "This message will be sent when the button is clicked" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "버튼을 클릭하면 이 메시지가 전송됩니다" + "This message will be sent when the button is clicked": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "This message will be sent when the button is clicked" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "点击按钮时会发送此消息" - } - } - } - }, - "Todos" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Todos" + "ko": { + "stringUnit": { + "state": "translated", + "value": "버튼을 클릭하면 이 메시지가 전송됩니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "待办" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "点击按钮时会发送此消息" } } } }, - "Toggle fast mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Toggle fast mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "빠른 모드 켜기/끄기" + "Todos": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Todos" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "切换快速模式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "待办" } } } }, - "Toggle sandbox mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Toggle sandbox mode" + "Toggle fast mode": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Toggle fast mode" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "샌드박스 모드 전환" + "ko": { + "stringUnit": { + "state": "translated", + "value": "빠른 모드 켜기/끄기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "切换沙盒模式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "切换快速模式" } } } }, - "Toggle voice dictation" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Toggle voice dictation" + "Toggle sandbox mode": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Toggle sandbox mode" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "음성 받아쓰기 전환" + "ko": { + "stringUnit": { + "state": "translated", + "value": "샌드박스 모드 전환" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "切换语音听写" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "切换沙盒模式" } } } }, - "tok" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "tok" + "Toggle voice dictation": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Toggle voice dictation" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "토큰" + "ko": { + "stringUnit": { + "state": "translated", + "value": "음성 받아쓰기 전환" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "tok" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "切换语音听写" } } } }, - "Token usage statistics" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Token usage statistics" + "tok": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "tok" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "토큰 사용 통계" + "ko": { + "stringUnit": { + "state": "translated", + "value": "토큰" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Token 用量统计" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "tok" } } } }, - "tokens" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "tokens" + "Token usage statistics": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Token usage statistics" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "토큰" + "ko": { + "stringUnit": { + "state": "translated", + "value": "토큰 사용 통계" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "token" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "Token 用量统计" } } } }, - "Tracks usage against Anthropic's rolling 5-hour limit. Resets gradually as older requests age out." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Tracks usage against Anthropic's rolling 5-hour limit. Resets gradually as older requests age out." + "Tracks usage against Anthropic's rolling 5-hour limit. Resets gradually as older requests age out.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Tracks usage against Anthropic's rolling 5-hour limit. Resets gradually as older requests age out." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Anthropic의 5시간 롤링 한도 대비 사용량을 추적합니다. 이전 요청이 시간이 지남에 따라 점진적으로 리셋됩니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "Anthropic의 5시간 롤링 한도 대비 사용량을 추적합니다. 이전 요청이 시간이 지남에 따라 점진적으로 리셋됩니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "跟踪 Anthropic 5 小时滚动限制的用量。旧请求过期后会逐步恢复。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "跟踪 Anthropic 5 小时滚动限制的用量。旧请求过期后会逐步恢复。" } } } }, - "Tracks usage against Anthropic's rolling 7-day limit. Resets gradually as older requests age out." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Tracks usage against Anthropic's rolling 7-day limit. Resets gradually as older requests age out." + "Tracks usage against Anthropic's rolling 7-day limit. Resets gradually as older requests age out.": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Tracks usage against Anthropic's rolling 7-day limit. Resets gradually as older requests age out." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Anthropic의 7일 롤링 한도 대비 사용량을 추적합니다. 이전 요청이 시간이 지남에 따라 점진적으로 리셋됩니다." + "ko": { + "stringUnit": { + "state": "translated", + "value": "Anthropic의 7일 롤링 한도 대비 사용량을 추적합니다. 이전 요청이 시간이 지남에 따라 점진적으로 리셋됩니다." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "跟踪 Anthropic 7 天滚动限制的用量。旧请求过期后会逐步恢复。" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "跟踪 Anthropic 7 天滚动限制的用量。旧请求过期后会逐步恢复。" } } } }, - "Tracks usage against Codex's rolling 5-hour limit. Resets gradually as older requests age out." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "跟踪 Codex 滚动 5 小时限制下的用量。较早请求过期后会逐步重置。" + "Tracks usage against Codex's rolling 5-hour limit. Resets gradually as older requests age out.": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "跟踪 Codex 滚动 5 小时限制下的用量。较早请求过期后会逐步重置。" } } } }, - "Tracks usage against Codex's rolling 7-day limit. Resets gradually as older requests age out." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "跟踪 Codex 滚动 7 天限制下的用量。较早请求过期后会逐步重置。" + "Tracks usage against Codex's rolling 7-day limit. Resets gradually as older requests age out.": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "跟踪 Codex 滚动 7 天限制下的用量。较早请求过期后会逐步重置。" } } } }, - "Try a different keyword" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Try a different keyword" + "Try a different keyword": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Try a different keyword" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "다른 키워드로 검색해 보세요" + "ko": { + "stringUnit": { + "state": "translated", + "value": "다른 키워드로 검색해 보세요" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "尝试其他关键词" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "尝试其他关键词" } } } }, - "Turn off plan mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Turn off plan mode" + "Turn off plan mode": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Turn off plan mode" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "플랜 모드 끄기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "플랜 모드 끄기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "关闭计划模式" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "关闭计划模式" } } } }, - "Turns" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Turns" + "Turns": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Turns" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대화 횟수" + "ko": { + "stringUnit": { + "state": "translated", + "value": "대화 횟수" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "轮次" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "轮次" } } } }, - "Type a message..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Type a message..." + "Type a message...": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Type a message..." } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지를 입력하세요..." + "ko": { + "stringUnit": { + "state": "translated", + "value": "메시지를 입력하세요..." } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输入消息..." + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "输入消息..." } } } }, - "Upgrade plan" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Upgrade plan" + "Upgrade plan": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Upgrade plan" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상위 요금제로 업그레이드" + "ko": { + "stringUnit": { + "state": "translated", + "value": "상위 요금제로 업그레이드" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "升级套餐" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "升级套餐" } } } }, - "Usage" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Usage" + "Usage": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Usage" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사용량" + "ko": { + "stringUnit": { + "state": "translated", + "value": "사용량" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "用量" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用量" } } } }, - "Usage:" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Usage:" + "Usage:": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Usage:" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사용법:" + "ko": { + "stringUnit": { + "state": "translated", + "value": "사용법:" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "用法:" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "用法:" } } } }, - "Use the Add menu or Shift-Tab to ask the agent for a read-only plan before edits begin." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在开始编辑前,使用“添加”菜单或 Shift-Tab 请求智能体提供只读计划。" + "Use the Add menu or Shift-Tab to ask the agent for a read-only plan before edits begin.": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "在开始编辑前,使用“添加”菜单或 Shift-Tab 请求智能体提供只读计划。" } } } }, - "Version, model, and account status" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Version, model, and account status" + "Version, model, and account status": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Version, model, and account status" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "버전, 모델, 계정 상태" + "ko": { + "stringUnit": { + "state": "translated", + "value": "버전, 모델, 계정 상태" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "版本、模型和账号状态" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "版本、模型和账号状态" } } } }, - "View" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查看" + "View": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看" } } } }, - "View changelog" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "View changelog" + "View changelog": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "View changelog" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "변경 로그 보기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "변경 로그 보기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查看更新日志" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看更新日志" } } } }, - "View hook configuration" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "View hook configuration" + "View hook configuration": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "View hook configuration" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "훅 구성 보기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "훅 구성 보기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查看 hook 配置" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看 hook 配置" } } } }, - "View Result" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "View Result" + "View Result": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "View Result" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "결과 보기" + "ko": { + "stringUnit": { + "state": "translated", + "value": "결과 보기" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查看结果" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "查看结果" } } } }, - "Visualize context usage" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Visualize context usage" + "Visualize context usage": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Visualize context usage" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "컨텍스트 사용량 시각화" + "ko": { + "stringUnit": { + "state": "translated", + "value": "컨텍스트 사용량 시각화" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "可视化上下文用量" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "可视化上下文用量" } } } }, - "Waiting for answer" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "等待回答" + "Waiting for answer": { + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "等待回答" } } } }, - "What should we build in %@?" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What should we build in %@?" + "What should we build in %@?": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "What should we build in %@?" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "我们要在 %@ 中构建什么?" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "我们要在 %@ 中构建什么?" } } } }, - "What would you like changed?" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What would you like changed?" + "What would you like changed?": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "What would you like changed?" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "你希望修改什么?" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "你希望修改什么?" } } } }, - "When enabled, the command runs in the terminal instead of chat" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "When enabled, the command runs in the terminal instead of chat" + "When enabled, the command runs in the terminal instead of chat": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "When enabled, the command runs in the terminal instead of chat" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "활성화하면 커맨드가 채팅 대신 터미널에서 실행됩니다" + "ko": { + "stringUnit": { + "state": "translated", + "value": "활성화하면 커맨드가 채팅 대신 터미널에서 실행됩니다" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用后,命令会在终端中运行,而不是发送到聊天" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "启用后,命令会在终端中运行,而不是发送到聊天" } } } }, - "Write heap snapshot for memory diagnostics" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Write heap snapshot for memory diagnostics" + "Write heap snapshot for memory diagnostics": { + "localizations": { + "en": { + "stringUnit": { + "state": "new", + "value": "Write heap snapshot for memory diagnostics" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메모리 진단을 위한 힙 스냅샷 저장" + "ko": { + "stringUnit": { + "state": "translated", + "value": "메모리 진단을 위한 힙 스냅샷 저장" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "写入堆快照以进行内存诊断" + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "写入堆快照以进行内存诊断" } } } } }, - "version" : "1.1" -} \ No newline at end of file + "version": "1.1" +} diff --git a/Packages/Sources/RxCodeChatKit/ToolResultView.swift b/Packages/Sources/RxCodeChatKit/ToolResultView.swift index 51308abc..dbca3827 100644 --- a/Packages/Sources/RxCodeChatKit/ToolResultView.swift +++ b/Packages/Sources/RxCodeChatKit/ToolResultView.swift @@ -7,7 +7,7 @@ struct ToolResultView: View { @State private var isExpanded: Bool @State private var isDiffExpanded = false @State private var showBashSheet = false - @State private var showMCPDetailSheet = false + @State private var showDetailSheet = false @Environment(WindowState.self) private var windowState /// Lowercased tool name (avoids repeated lowercased() calls) @@ -157,6 +157,15 @@ struct ToolResultView: View { ClaudeThemeDivider() fileChangeDiffsView(toolCall.fileChangeDiffs) } + } else if toolNameLower == "write", + let content = toolCall.input["content"]?.stringValue { + // Write creates a new file — render the content as a + // pure-additions diff so the user sees `+` markers and + // green highlighting just like an Edit. + VStack(alignment: .leading, spacing: 6) { + ClaudeThemeDivider() + editDiffView(oldString: "", newString: content) + } } else if let result = toolCall.result, !result.isEmpty { VStack(alignment: .leading, spacing: 6) { ClaudeThemeDivider() @@ -197,14 +206,18 @@ struct ToolResultView: View { private var minimalBody: some View { VStack(alignment: .leading, spacing: 4) { Button { - if isMCPTool { - showMCPDetailSheet = true - } else if isBashTool, toolCall.result != nil { + if isBashTool, toolCall.result != nil { showBashSheet = true + } else if isMCPTool { + showDetailSheet = true } else { +#if os(iOS) + showDetailSheet = true +#else withAnimation(.easeInOut(duration: 0.2)) { isExpanded.toggle() } +#endif } } label: { HStack(spacing: 6) { @@ -235,6 +248,7 @@ struct ToolResultView: View { } .buttonStyle(.plain) +#if os(macOS) if isExpanded, !isBashTool, !isMCPTool, let result = toolCall.result, !result.isEmpty { ScrollView { ChatTextContentView( @@ -248,13 +262,14 @@ struct ToolResultView: View { .frame(maxHeight: 200) .padding(.leading, 20) } +#endif } .sheet(isPresented: $showBashSheet) { BashTerminalSheet(toolCall: toolCall) } - .sheet(isPresented: $showMCPDetailSheet) { - MCPToolDetailSheet(toolCall: toolCall) - .mcpToolDetailSheetPresentation() + .sheet(isPresented: $showDetailSheet) { + ToolCallDetailSheet(toolCall: toolCall) + .toolCallDetailSheetPresentation() } } @@ -283,15 +298,21 @@ struct ToolResultView: View { } private var hasExpandableContent: Bool { - isEditTool && ( - (toolCall.input["old_string"]?.stringValue != nil - && toolCall.input["new_string"]?.stringValue != nil) - || !toolCall.fileChangeDiffs.isEmpty - ) + if isEditTool, (toolCall.input["old_string"]?.stringValue != nil + && toolCall.input["new_string"]?.stringValue != nil) { + return true + } + if isEditTool, !toolCall.fileChangeDiffs.isEmpty { + return true + } + if toolNameLower == "write", toolCall.input["content"]?.stringValue != nil { + return true + } + return false } private func editHunksFromToolInput() -> [PreviewFile.EditHunk] { - guard isEditTool else { return [] } + guard isEditTool || toolNameLower == "write" else { return [] } return toolCall.fileEditHunks } @@ -300,8 +321,13 @@ struct ToolResultView: View { old: oldString.components(separatedBy: .newlines), new: newString.components(separatedBy: .newlines) ) - let removedLines = trimmedOld.map { ("-", $0, false) } - let addedLines = trimmedNew.map { ("+", $0, true) } + // When oldString is fully empty (new file creation) the split yields a + // single empty line that renders as a lone `-` row above the content. + // Drop it so the diff is purely additions. + let removedSource = oldString.isEmpty ? [] : trimmedOld + let addedSource = newString.isEmpty ? [] : trimmedNew + let removedLines = removedSource.map { ("-", $0, false) } + let addedLines = addedSource.map { ("+", $0, true) } let allLines = removedLines + addedLines let collapseThreshold = 12 @@ -382,7 +408,18 @@ struct ToolResultView: View { } private func rawUnifiedDiffView(_ diff: String) -> some View { - let lines = diff.components(separatedBy: .newlines) + let rawLines = diff.components(separatedBy: .newlines) + // Codex's `changes[].diff` for a brand-new file is sometimes just the + // file's content with no `+`/`-`/`@@` markers. Without prefixes the + // renderer would draw every line as plain text — exactly the + // "no diff changes shown" symptom. Detect that shape and synthesize + // `+` prefixes so additions render in green. + let hasAnyMarker = rawLines.contains { + $0.hasPrefix("+") || $0.hasPrefix("-") || $0.hasPrefix("@@") + } + let lines: [String] = hasAnyMarker ? rawLines : rawLines.map { line in + line.isEmpty ? line : "+" + line + } let collapseThreshold = 18 let needsToggle = lines.count > collapseThreshold let visibleLines = needsToggle && !isDiffExpanded @@ -500,7 +537,7 @@ struct ToolResultView: View { fileActionLink(label: fileName, color: ClaudeTheme.accent) { windowState.inspectorFile = PreviewFile(path: filePath, name: fileName) } - if isEditTool, toolCall.result != nil { + if (isEditTool || toolNameLower == "write"), toolCall.result != nil { let hunks = editHunksFromToolInput() if !hunks.isEmpty { HStack(spacing: 0) { @@ -616,14 +653,14 @@ struct ToolResultView: View { } } -struct MCPToolDetailSheet: View { +struct ToolCallDetailSheet: View { let toolCall: ToolCall @Environment(\.dismiss) private var dismiss var body: some View { VStack(alignment: .leading, spacing: 0) { HStack(spacing: 10) { - Image(systemName: "puzzlepiece.extension") + Image(systemName: iconName) .font(.system(size: ClaudeTheme.messageSize(16), weight: .medium)) .foregroundStyle(ClaudeTheme.accent) @@ -660,17 +697,40 @@ struct MCPToolDetailSheet: View { .padding(16) } } - .mcpToolDetailFrame() + .toolCallDetailFrame() .background(ClaudeTheme.surfacePrimary) } + private var toolNameLower: String { toolCall.name.lowercased() } + private var isMCP: Bool { ToolCategory(toolName: toolCall.name) == .mcp } + + private var iconName: String { + if isMCP { return "puzzlepiece.extension" } + switch toolNameLower { + case "agent": return "cpu" + case "read": return "doc.text" + case "grep", "glob": return "magnifyingglass" + case "write": return "square.and.pencil" + case "edit", + "multiedit", + "multi_edit": return "pencil" + case "bash": return "terminal" + case "notebookedit": return "book.and.wrench" + case "skill": return "sparkles" + default: return ToolCategory(toolName: toolNameLower).sfSymbol + } + } + private var displayName: String { - if toolCall.name.lowercased() == "mcptoolcall" { - return "MCP tool call" + if isMCP { + if toolNameLower == "mcptoolcall" { + return "MCP tool call" + } + return toolCall.name + .replacingOccurrences(of: "mcp__", with: "") + .replacingOccurrences(of: "__", with: " / ") } return toolCall.name - .replacingOccurrences(of: "mcp__", with: "") - .replacingOccurrences(of: "__", with: " / ") } private var statusText: String { @@ -714,7 +774,7 @@ struct MCPToolDetailSheet: View { private extension View { @ViewBuilder - func mcpToolDetailSheetPresentation() -> some View { + func toolCallDetailSheetPresentation() -> some View { #if os(iOS) self .presentationDetents([.large]) @@ -725,7 +785,7 @@ private extension View { } @ViewBuilder - func mcpToolDetailFrame() -> some View { + func toolCallDetailFrame() -> some View { #if os(macOS) self.frame(minWidth: 640, minHeight: 460) #else diff --git a/Packages/Sources/RxCodeCore/Models/ChatMessage.swift b/Packages/Sources/RxCodeCore/Models/ChatMessage.swift index e8be47f3..8f3affd2 100644 --- a/Packages/Sources/RxCodeCore/Models/ChatMessage.swift +++ b/Packages/Sources/RxCodeCore/Models/ChatMessage.swift @@ -284,9 +284,20 @@ public extension ToolCall { /// body so Codex `fileChange` calls can flow through the same /// `ThreadFileEdit` storage as Claude Edit/MultiEdit/Write. public var hunk: PreviewFile.EditHunk { + let rawLines = diff.components(separatedBy: "\n") + // Some agents (notably Codex on new-file creation) emit `diff` as + // the file's plain content with no `+`/`-`/`@@` markers. Treat + // that as an all-additions hunk so sidebar counts and the diff + // renderer don't collapse to empty. + let hasAnyMarker = rawLines.contains { + $0.hasPrefix("+") || $0.hasPrefix("-") || $0.hasPrefix("@@") + } + if !hasAnyMarker { + return PreviewFile.EditHunk(oldString: "", newString: diff) + } var removed: [String] = [] var added: [String] = [] - for rawLine in diff.components(separatedBy: "\n") { + for rawLine in rawLines { if rawLine.hasPrefix("---") || rawLine.hasPrefix("+++") { continue } if rawLine.hasPrefix("@@") { continue } if rawLine.hasPrefix("-") { @@ -358,22 +369,28 @@ public struct FileEditSummary: Identifiable, Sendable { /// not surgically edited. public let containsWrite: Bool /// File contents captured at the moment this thread first touched the path. - /// When present, the diff view uses it as the "before" side and the - /// current file on disk as the "after" side, instead of reconstructing - /// from hunks. + /// Fixed once set — never overwritten by subsequent edits in the same thread. + /// Acts as the "before" side of the snapshot-pair diff. public let originalContent: String? + /// File contents re-read from disk after each successful edit tool_result + /// in this thread. Overwritten on every subsequent edit so the "after" + /// side always reflects this thread's most recent committed state, + /// independent of any concurrent edits from other threads/agents. + public let modifiedContent: String? public init( path: String, name: String, hunks: [PreviewFile.EditHunk], containsWrite: Bool, - originalContent: String? = nil + originalContent: String? = nil, + modifiedContent: String? = nil ) { self.path = path self.name = name self.hunks = hunks self.containsWrite = containsWrite self.originalContent = originalContent + self.modifiedContent = modifiedContent } } diff --git a/Packages/Sources/RxCodeCore/Models/PreviewFile.swift b/Packages/Sources/RxCodeCore/Models/PreviewFile.swift index 7dfbd9d7..97995c32 100644 --- a/Packages/Sources/RxCodeCore/Models/PreviewFile.swift +++ b/Packages/Sources/RxCodeCore/Models/PreviewFile.swift @@ -28,10 +28,15 @@ public struct PreviewFile: Identifiable, Sendable { public let gitDiffMode: GitDiffMode? public let showFullFileDiff: Bool /// File contents captured before this thread's first edit to the path. - /// When non-nil, `FileDiffView` diffs this snapshot against the current - /// on-disk content and ignores `editHunks` — yielding an exact diff even - /// when other agents have concurrently modified the file. + /// Fixed once set; together with `modifiedContent` forms the snapshot pair + /// that `FileDiffView` diffs to render this thread's changes. public let originalContent: String? + /// File contents captured immediately after the thread's most recent edit + /// tool_result. When both `originalContent` and `modifiedContent` are + /// present `FileDiffView` diffs them directly and ignores `editHunks` and + /// the current on-disk content — giving an exact, thread-isolated diff + /// even when other agents concurrently modify the file. + public let modifiedContent: String? public init( path: String, @@ -39,7 +44,8 @@ public struct PreviewFile: Identifiable, Sendable { editHunks: [EditHunk] = [], gitDiffMode: GitDiffMode? = nil, showFullFileDiff: Bool = false, - originalContent: String? = nil + originalContent: String? = nil, + modifiedContent: String? = nil ) { self.path = path self.name = name @@ -47,5 +53,6 @@ public struct PreviewFile: Identifiable, Sendable { self.gitDiffMode = gitDiffMode self.showFullFileDiff = showFullFileDiff self.originalContent = originalContent + self.modifiedContent = modifiedContent } } diff --git a/Packages/Sources/RxCodeCore/Models/ThreadFileEdit.swift b/Packages/Sources/RxCodeCore/Models/ThreadFileEdit.swift index c800958d..9cb2b418 100644 --- a/Packages/Sources/RxCodeCore/Models/ThreadFileEdit.swift +++ b/Packages/Sources/RxCodeCore/Models/ThreadFileEdit.swift @@ -15,11 +15,15 @@ public final class ThreadFileEdit { public var firstEditedAt: Date public var updatedAt: Date /// Full file content captured the first time this session's stream sees an - /// Edit/MultiEdit/Write tool_use for this path. Used by the diff inspector - /// as the "before" side of the diff so concurrent edits from other agents - /// don't break hunk anchoring. Optional for legacy rows persisted before - /// snapshot capture was added — those still render via hunk reverse-apply. + /// Edit/MultiEdit/Write tool_use for this path. Fixed forever once set — + /// the "before" side of the snapshot-pair diff. Optional for legacy rows + /// persisted before snapshot capture was added. public var originalContent: String? + /// Full file content re-read from disk after each successful edit + /// tool_result for this path. Overwritten on every subsequent edit so the + /// "after" side always reflects this thread's most recent committed state. + /// Optional for legacy rows; consumers fall back to disk read / hunks. + public var modifiedContent: String? public init( sessionId: String, @@ -28,6 +32,7 @@ public final class ThreadFileEdit { hunks: [PreviewFile.EditHunk], containsWrite: Bool, originalContent: String? = nil, + modifiedContent: String? = nil, firstEditedAt: Date = .now, updatedAt: Date = .now ) { @@ -37,6 +42,7 @@ public final class ThreadFileEdit { self.containsWrite = containsWrite self.hunksData = Self.encode(hunks) self.originalContent = originalContent + self.modifiedContent = modifiedContent self.firstEditedAt = firstEditedAt self.updatedAt = updatedAt } @@ -57,7 +63,14 @@ public final class ThreadFileEdit { } public func toSummary() -> FileEditSummary { - FileEditSummary(path: path, name: name, hunks: hunks, containsWrite: containsWrite, originalContent: originalContent) + FileEditSummary( + path: path, + name: name, + hunks: hunks, + containsWrite: containsWrite, + originalContent: originalContent, + modifiedContent: modifiedContent + ) } private static func encode(_ hunks: [PreviewFile.EditHunk]) -> Data { diff --git a/Packages/Sources/RxCodeCore/Utilities/GitHelper.swift b/Packages/Sources/RxCodeCore/Utilities/GitHelper.swift index 0bdb1134..9c361898 100644 --- a/Packages/Sources/RxCodeCore/Utilities/GitHelper.swift +++ b/Packages/Sources/RxCodeCore/Utilities/GitHelper.swift @@ -67,6 +67,12 @@ public enum GitHelper { return trimmed.isEmpty ? nil : trimmed } + /// Runs `git init` at `path`. Returns nil on success or the combined git + /// output on failure. + public static func initRepository(at path: String) async -> String? { + await runWithError(["init"], at: path) + } + /// Checks out an existing branch at `path`. Returns the combined git output /// on failure, or nil on success. public static func checkout(branch: String, at path: String) async -> String? { diff --git a/Packages/Sources/RxCodeCore/Utilities/SyntaxHighlighter.swift b/Packages/Sources/RxCodeCore/Utilities/SyntaxHighlighter.swift index 19129ab5..29eba89d 100644 --- a/Packages/Sources/RxCodeCore/Utilities/SyntaxHighlighter.swift +++ b/Packages/Sources/RxCodeCore/Utilities/SyntaxHighlighter.swift @@ -55,6 +55,13 @@ public enum SyntaxHighlighter { return result } + /// Extract a language identifier from a filename (or path). Returns the + /// lowercased extension, or `nil` when the file has no extension. + public static func language(forFilename filename: String) -> String? { + let ext = (filename as NSString).pathExtension + return ext.isEmpty ? nil : ext.lowercased() + } + // Normalize markdown language names → file extensions public static func normalizeLanguage(_ language: String) -> String { switch language.lowercased() { diff --git a/Packages/Sources/RxCodeSync/Protocol/Payload+Sessions.swift b/Packages/Sources/RxCodeSync/Protocol/Payload+Sessions.swift index cdf2e409..89f909db 100644 --- a/Packages/Sources/RxCodeSync/Protocol/Payload+Sessions.swift +++ b/Packages/Sources/RxCodeSync/Protocol/Payload+Sessions.swift @@ -392,19 +392,46 @@ public struct SyncFileEdit: Codable, Sendable, Identifiable { /// Optional full-file before/after diff for mobile detail views. Older /// desktop builds omit this and mobile falls back to `hunks`. public let fullFileDiff: String? + /// Pre-edit snapshot ("before" side of the snapshot-pair diff). Optional — + /// older desktop builds omit it. + public let originalContent: String? + /// Post-edit snapshot captured after this thread's most recent edit ("after" + /// side of the snapshot-pair diff). When both `originalContent` and + /// `modifiedContent` are present, mobile renders the diff directly from + /// them and ignores `fullFileDiff` / `hunks`. + public let modifiedContent: String? public init( path: String, name: String, containsWrite: Bool, hunks: [SyncEditHunk], - fullFileDiff: String? = nil + fullFileDiff: String? = nil, + originalContent: String? = nil, + modifiedContent: String? = nil ) { self.path = path self.name = name self.containsWrite = containsWrite self.hunks = hunks self.fullFileDiff = fullFileDiff + self.originalContent = originalContent + self.modifiedContent = modifiedContent + } + + private enum CodingKeys: String, CodingKey { + case path, name, containsWrite, hunks, fullFileDiff, originalContent, modifiedContent + } + + public init(from decoder: Decoder) throws { + let c = try decoder.container(keyedBy: CodingKeys.self) + self.path = try c.decode(String.self, forKey: .path) + self.name = try c.decode(String.self, forKey: .name) + self.containsWrite = try c.decode(Bool.self, forKey: .containsWrite) + self.hunks = try c.decode([SyncEditHunk].self, forKey: .hunks) + self.fullFileDiff = try c.decodeIfPresent(String.self, forKey: .fullFileDiff) + self.originalContent = try c.decodeIfPresent(String.self, forKey: .originalContent) + self.modifiedContent = try c.decodeIfPresent(String.self, forKey: .modifiedContent) } } diff --git a/Packages/Sources/RxCodeSync/Protocol/Payload.swift b/Packages/Sources/RxCodeSync/Protocol/Payload.swift index 92fce56a..5fcc470d 100644 --- a/Packages/Sources/RxCodeSync/Protocol/Payload.swift +++ b/Packages/Sources/RxCodeSync/Protocol/Payload.swift @@ -446,6 +446,7 @@ public struct BranchOpRequestPayload: Codable, Sendable { public enum Operation: String, Codable, Sendable { case switchExisting case createNew + case initGit } public let clientRequestID: UUID diff --git a/Packages/Tests/DiffViewTests/DiffComputationTests.swift b/Packages/Tests/DiffViewTests/DiffComputationTests.swift new file mode 100644 index 00000000..e4b49300 --- /dev/null +++ b/Packages/Tests/DiffViewTests/DiffComputationTests.swift @@ -0,0 +1,223 @@ +import Testing +import RxCodeCore +@testable import DiffView + +@Suite("DiffComputation") +@MainActor +struct DiffComputationTests { + @Test("snapshot diff numbers both gutters") + func snapshotDiffNumbersBothGutters() { + let lines = DiffComputation.buildSnapshotDiffLines( + original: "one\ntwo\nthree\n", + current: "one\nTWO\nthree\n" + ) + + #expect(lines.map(\.text) == [" one", "-two", "+TWO", " three"]) + #expect(lines[0].oldLineNumber == 1 && lines[0].newLineNumber == 1) + #expect(lines[1].oldLineNumber == 2 && lines[1].newLineNumber == nil) + #expect(lines[2].oldLineNumber == nil && lines[2].newLineNumber == 2) + #expect(lines[3].oldLineNumber == 3 && lines[3].newLineNumber == 3) + } + + @Test("new-file snapshot diff yields only added lines") + func newFileSnapshotDiffOnlyAdded() { + let lines = DiffComputation.buildSnapshotDiffLines( + original: "", + current: "alpha\nbeta\n" + ) + + #expect(lines.allSatisfy { $0.kind == .added }) + #expect(lines.allSatisfy { $0.oldLineNumber == nil }) + #expect(lines.compactMap(\.newLineNumber) == [1, 2]) + } + + @Test("snapshot diff added/removed counts lock the sidebar contract") + func snapshotDiffCountsMatchSidebar() { + let lines = DiffComputation.buildSnapshotDiffLines( + original: "a\nb\nc\n", + current: "a\nB\nc\n" + ) + let added = lines.filter { $0.kind == .added }.count + let removed = lines.filter { $0.kind == .removed }.count + #expect(added == 1) + #expect(removed == 1) + } + + @Test("edit hunk diff strips common indent") + func editHunkStripsCommonIndent() { + let hunks = [ + PreviewFile.EditHunk(oldString: " foo\n bar", newString: " FOO\n bar") + ] + let lines = DiffComputation.buildEditDiffLines(from: hunks) + + #expect(lines.map(\.text) == ["-foo", "-bar", "+FOO", "+bar"]) + } + + @Test("edit hunk diff renders file creation as all-added with new gutter") + func editHunkRendersFileCreationAsAllAdded() { + let hunks = [ + PreviewFile.EditHunk(oldString: "", newString: "alpha\nbeta\ngamma\n") + ] + let lines = DiffComputation.buildEditDiffLines(from: hunks) + + #expect(lines.map(\.kind) == [.added, .added, .added]) + #expect(lines.map(\.text) == ["+alpha", "+beta", "+gamma"]) + #expect(lines.compactMap(\.newLineNumber) == [1, 2, 3]) + #expect(lines.allSatisfy { $0.oldLineNumber == nil }) + } + + @Test("edit hunk diff renders file deletion as all-removed with old gutter") + func editHunkRendersFileDeletionAsAllRemoved() { + let hunks = [ + PreviewFile.EditHunk(oldString: "alpha\nbeta\n", newString: "") + ] + let lines = DiffComputation.buildEditDiffLines(from: hunks) + + #expect(lines.map(\.kind) == [.removed, .removed]) + #expect(lines.map(\.text) == ["-alpha", "-beta"]) + #expect(lines.compactMap(\.oldLineNumber) == [1, 2]) + #expect(lines.allSatisfy { $0.newLineNumber == nil }) + } + + @Test("full-file edit diff reconstructs the pre-edit file") + func fullFileEditDiffReconstructsPreEdit() { + let hunk = PreviewFile.EditHunk(oldString: "two", newString: "TWO") + let lines = DiffComputation.buildFullFileEditDiffLines( + currentContent: "one\nTWO\nthree\n", + hunks: [hunk] + ) + + #expect(lines.map(\.text) == [" one", "-two", "+TWO", " three"]) + } + + @Test("full-file edit diff reconstructs multiple edits in reverse order") + func fullFileEditDiffReconstructsMultipleEdits() { + let hunks = [ + PreviewFile.EditHunk(oldString: "alpha", newString: "ALPHA"), + PreviewFile.EditHunk(oldString: "gamma", newString: "GAMMA"), + ] + let lines = DiffComputation.buildFullFileEditDiffLines( + currentContent: "ALPHA\nbeta\nGAMMA\n", + hunks: hunks + ) + + #expect(lines.map(\.text) == [ + "-alpha", + "+ALPHA", + " beta", + "-gamma", + "+GAMMA", + ]) + } + + @Test("full-file edit diff shows orphan change when reconstruction fails") + func fullFileEditDiffShowsOrphanWhenReconstructionFails() { + let hunk = PreviewFile.EditHunk(oldString: "before", newString: "after") + let lines = DiffComputation.buildFullFileEditDiffLines( + currentContent: "import SwiftUI\n\nstruct Example {}\n", + hunks: [hunk] + ) + + #expect(lines.map(\.text) == [ + "@@ unmatched change @@", + "-before", + "+after", + " import SwiftUI", + " ", + " struct Example {}", + ]) + } + + @Test("full-file edit diff shows pure deletion as orphan above full file") + func fullFileEditDiffShowsPureDeletionAsOrphan() { + let hunk = PreviewFile.EditHunk( + oldString: " guard Self.hasExplicitMemoryIntent(userMessage) else { return }", + newString: "" + ) + let current = " let userMessage = lastUserMessageText(in: messages)\n let finalResponse = lastAssistantResponseText(in: messages)\n let sourceMessageId = nil\n" + let lines = DiffComputation.buildFullFileEditDiffLines( + currentContent: current, + hunks: [hunk] + ) + + #expect(lines.map(\.text) == [ + "@@ unmatched change @@", + "- guard Self.hasExplicitMemoryIntent(userMessage) else { return }", + " let userMessage = lastUserMessageText(in: messages)", + " let finalResponse = lastAssistantResponseText(in: messages)", + " let sourceMessageId = nil", + ]) + } + + @Test("full-file edit diff renders a Write as all-added lines") + func fullFileEditDiffRendersWriteAsAllAdded() { + let content = "line one\nline two\nline three\n" + let hunk = PreviewFile.EditHunk(oldString: "", newString: content) + let lines = DiffComputation.buildFullFileEditDiffLines( + currentContent: content, + hunks: [hunk] + ) + + #expect(lines.map(\.text) == [ + "+line one", + "+line two", + "+line three", + ]) + } + + @Test("snapshot diff line numbers track both sides") + func snapshotDiffLineNumbersTrackBothSides() { + let original = "alpha\nbeta\ngamma\n" + let current = "alpha\nBETA\ngamma\ndelta\n" + let lines = DiffComputation.buildSnapshotDiffLines( + original: original, + current: current + ) + + #expect(lines.map(\.text) == [ + " alpha", + "-beta", + "+BETA", + " gamma", + "+delta", + ]) + #expect(lines.map(\.oldLineNumber) == [1, 2, nil, 3, nil]) + #expect(lines.map(\.newLineNumber) == [1, nil, 2, 3, 4]) + } + + @Test("full-file edit diff renders an addition with surrounding context") + func fullFileEditDiffRendersAdditionWithContext() { + let hunk = PreviewFile.EditHunk( + oldString: "alpha\nbeta", + newString: "alpha\n// inserted comment\nbeta" + ) + let current = "alpha\n// inserted comment\nbeta\n" + let lines = DiffComputation.buildFullFileEditDiffLines( + currentContent: current, + hunks: [hunk] + ) + + #expect(lines.map(\.text) == [ + " alpha", + "+// inserted comment", + " beta", + ]) + } + + @Test("unified diff parser tracks gutter line numbers from hunk header") + func unifiedDiffParserTracksLineNumbers() { + let raw = """ + @@ -10,3 +10,3 @@ + keep + -old + +new + """ + let lines = DiffComputation.parseUnifiedDiff(raw) + + #expect(lines.count == 4) + #expect(lines[0].kind == .hunk) + #expect(lines[1].kind == .context && lines[1].oldLineNumber == 10 && lines[1].newLineNumber == 10) + #expect(lines[2].kind == .removed && lines[2].oldLineNumber == 11 && lines[2].newLineNumber == nil) + #expect(lines[3].kind == .added && lines[3].oldLineNumber == nil && lines[3].newLineNumber == 11) + } +} diff --git a/Packages/Tests/DiffViewTests/GutterLayoutTests.swift b/Packages/Tests/DiffViewTests/GutterLayoutTests.swift new file mode 100644 index 00000000..afd97c0b --- /dev/null +++ b/Packages/Tests/DiffViewTests/GutterLayoutTests.swift @@ -0,0 +1,71 @@ +import Testing +@testable import DiffView + +@Suite("GutterLayout") +@MainActor +struct GutterLayoutTests { + @Test("change set with both sides uses two columns") + func changeUsesTwoColumns() { + let lines = [ + DiffLine(text: " a", kind: .context, oldLineNumber: 1, newLineNumber: 1), + DiffLine(text: "-b", kind: .removed, oldLineNumber: 2, newLineNumber: nil), + DiffLine(text: "+B", kind: .added, oldLineNumber: nil, newLineNumber: 2), + ] + let layout = GutterLayout(lines: lines) + + #expect(layout.showOld) + #expect(layout.showNew) + #expect(layout.columnCount == 2) + } + + @Test("new-file diff (only added rows) collapses to one column") + func newFileUsesOneColumn() { + let lines = [ + DiffLine(text: "+alpha", kind: .added, oldLineNumber: nil, newLineNumber: 1), + DiffLine(text: "+beta", kind: .added, oldLineNumber: nil, newLineNumber: 2), + ] + let layout = GutterLayout(lines: lines) + + #expect(layout.showOld == false) + #expect(layout.showNew) + #expect(layout.columnCount == 1) + } + + @Test("full deletion (only removed rows) collapses to one column") + func deletedFileUsesOneColumn() { + let lines = [ + DiffLine(text: "-alpha", kind: .removed, oldLineNumber: 1, newLineNumber: nil), + DiffLine(text: "-beta", kind: .removed, oldLineNumber: 2, newLineNumber: nil), + ] + let layout = GutterLayout(lines: lines) + + #expect(layout.showOld) + #expect(layout.showNew == false) + #expect(layout.columnCount == 1) + } + + @Test("additions on top of context (no removals) collapses to new-only column") + func additionsOverContextUsesOneColumn() { + let lines = [ + DiffLine(text: " keep", kind: .context, oldLineNumber: 1, newLineNumber: 1), + DiffLine(text: "+new", kind: .added, oldLineNumber: nil, newLineNumber: 2), + DiffLine(text: " tail", kind: .context, oldLineNumber: 2, newLineNumber: 3), + ] + let layout = GutterLayout(lines: lines) + + #expect(layout.showOld == false) + #expect(layout.showNew) + #expect(layout.columnCount == 1) + } + + @Test("hunk-only edit preview with no line numbers shows no gutter") + func hunkOnlyShowsNoGutter() { + let lines = [ + DiffLine(text: "-foo", kind: .removed), + DiffLine(text: "+FOO", kind: .added), + ] + let layout = GutterLayout(lines: lines) + + #expect(layout.columnCount == 0) + } +} diff --git a/Packages/Tests/RxCodeChatKitTests/ChangeDiffViewTests.swift b/Packages/Tests/RxCodeChatKitTests/ChangeDiffViewTests.swift index ba1ff4ed..d70fb91c 100644 --- a/Packages/Tests/RxCodeChatKitTests/ChangeDiffViewTests.swift +++ b/Packages/Tests/RxCodeChatKitTests/ChangeDiffViewTests.swift @@ -7,27 +7,26 @@ import RxCodeCore @MainActor @Suite("ChangeDiffView rendering") struct ChangeDiffViewTests { - @Test("unified diff rows render a line number gutter") - func unifiedDiffRowsRenderLineNumbers() throws { - let view = ChangeDiffView(unifiedDiff: " one\n+two\n-three") + @Test("unified diff renders parsed lines through shared DiffView") + func unifiedDiffRendersParsedLines() throws { + let view = ChangeDiffView(unifiedDiff: "@@ -1,3 +1,3 @@\n one\n-two\n+TWO") let strings = try view.inspect().findAll(ViewType.Text.self).compactMap { try? $0.string() } - #expect(strings.contains("1")) - #expect(strings.contains("2")) - #expect(strings.contains("3")) - #expect(strings.contains("+two")) + // Each diff row renders marker + body as one concatenated Text, so we + // look for the marker-prefixed forms here. + #expect(strings.contains { $0.contains("one") }) + #expect(strings.contains { $0.contains("two") }) + #expect(strings.contains { $0.contains("TWO") }) } - @Test("hunk diff rows render a line number gutter") - func hunkDiffRowsRenderLineNumbers() throws { + @Test("hunk diff renders removed-then-added lines") + func hunkDiffRendersRemovedThenAdded() throws { let view = ChangeDiffView(hunks: [ PreviewFile.EditHunk(oldString: "old", newString: "new") ]) let strings = try view.inspect().findAll(ViewType.Text.self).compactMap { try? $0.string() } - #expect(strings.contains("1")) - #expect(strings.contains("2")) - #expect(strings.contains("- old")) - #expect(strings.contains("+ new")) + #expect(strings.contains { $0.contains("old") }) + #expect(strings.contains { $0.contains("new") }) } } diff --git a/Packages/Tests/RxCodeChatKitTests/FileDiffViewTests.swift b/Packages/Tests/RxCodeChatKitTests/FileDiffViewTests.swift deleted file mode 100644 index 6b1063da..00000000 --- a/Packages/Tests/RxCodeChatKitTests/FileDiffViewTests.swift +++ /dev/null @@ -1,151 +0,0 @@ -import Testing -import RxCodeCore -@testable import RxCodeChatKit - -@Suite("FileDiffView diff building") -@MainActor -struct FileDiffViewTests { - @Test("full-file edit diff includes unchanged context") - func fullFileEditDiffIncludesContext() { - let hunk = PreviewFile.EditHunk(oldString: "two", newString: "TWO") - let lines = FileDiffView.buildFullFileEditDiffLines( - currentContent: "one\nTWO\nthree\n", - hunks: [hunk] - ) - - #expect(lines.map(\.text) == [ - " one", - "-two", - "+TWO", - " three", - ]) - } - - @Test("full-file edit diff reconstructs multiple edits in reverse order") - func fullFileEditDiffReconstructsMultipleEdits() { - let hunks = [ - PreviewFile.EditHunk(oldString: "alpha", newString: "ALPHA"), - PreviewFile.EditHunk(oldString: "gamma", newString: "GAMMA"), - ] - let lines = FileDiffView.buildFullFileEditDiffLines( - currentContent: "ALPHA\nbeta\nGAMMA\n", - hunks: hunks - ) - - #expect(lines.map(\.text) == [ - "-alpha", - "+ALPHA", - " beta", - "-gamma", - "+GAMMA", - ]) - } - - @Test("full-file edit diff shows orphan change when reconstruction fails") - func fullFileEditDiffShowsOrphanWhenReconstructionFails() { - let hunk = PreviewFile.EditHunk(oldString: "before", newString: "after") - let lines = FileDiffView.buildFullFileEditDiffLines( - currentContent: "import SwiftUI\n\nstruct Example {}\n", - hunks: [hunk] - ) - - #expect(lines.map(\.text) == [ - "@@ unmatched change @@", - "-before", - "+after", - " import SwiftUI", - " ", - " struct Example {}", - ]) - } - - @Test("full-file edit diff shows pure deletion as orphan above full file") - func fullFileEditDiffShowsPureDeletionAsOrphan() { - // Pure deletion: hunk removes a line, replacing it with empty. - // The current file no longer contains the removed line, so we can't - // anchor it inline — it's surfaced as an orphan change at the top. - let hunk = PreviewFile.EditHunk( - oldString: " guard Self.hasExplicitMemoryIntent(userMessage) else { return }", - newString: "" - ) - let current = " let userMessage = lastUserMessageText(in: messages)\n let finalResponse = lastAssistantResponseText(in: messages)\n let sourceMessageId = nil\n" - let lines = FileDiffView.buildFullFileEditDiffLines( - currentContent: current, - hunks: [hunk] - ) - - #expect(lines.map(\.text) == [ - "@@ unmatched change @@", - "- guard Self.hasExplicitMemoryIntent(userMessage) else { return }", - " let userMessage = lastUserMessageText(in: messages)", - " let finalResponse = lastAssistantResponseText(in: messages)", - " let sourceMessageId = nil", - ]) - } - - @Test("full-file edit diff renders a Write as all-added lines") - func fullFileEditDiffRendersWriteAsAllAdded() { - // Write tool surfaces as a single hunk with empty oldString and the - // entire file as newString. Reverse-applied this clears the - // reconstructed pre-edit, so every current line shows as `+`. - let content = "line one\nline two\nline three\n" - let hunk = PreviewFile.EditHunk(oldString: "", newString: content) - let lines = FileDiffView.buildFullFileEditDiffLines( - currentContent: content, - hunks: [hunk] - ) - - #expect(lines.map(\.text) == [ - "+line one", - "+line two", - "+line three", - ]) - } - - @Test("snapshot diff renders exact changes between pre and post snapshots") - func snapshotDiffRendersExactChanges() { - // The new snapshot-based path doesn't reverse-apply hunks — it just - // diffs two full-file strings. Every line that differs shows up as - // -/+, every shared line as context. No orphan headers. - let original = "alpha\nbeta\ngamma\n" - let current = "alpha\nBETA\ngamma\ndelta\n" - let lines = FileDiffView.buildSnapshotDiffLines( - original: original, - current: current - ) - - #expect(lines.map(\.text) == [ - " alpha", - "-beta", - "+BETA", - " gamma", - "+delta", - ]) - // Old line numbers should track positions in the original snapshot. - #expect(lines.map(\.oldLineNumber) == [1, 2, nil, 3, nil]) - // New line numbers should track positions in the current file. - #expect(lines.map(\.newLineNumber) == [1, nil, 2, 3, 4]) - } - - @Test("full-file edit diff renders an addition with surrounding context") - func fullFileEditDiffRendersAdditionWithContext() { - // Realistic Edit hunk shape: oldString and newString both include the - // anchor line so the replacement is unique. The diff shows the new - // line inserted between alpha and beta. - let hunk = PreviewFile.EditHunk( - oldString: "alpha\nbeta", - newString: "alpha\n// inserted comment\nbeta" - ) - let current = "alpha\n// inserted comment\nbeta\n" - let lines = FileDiffView.buildFullFileEditDiffLines( - currentContent: current, - hunks: [hunk] - ) - - #expect(lines.map(\.text) == [ - " alpha", - "+// inserted comment", - " beta", - ]) - } -} diff --git a/Packages/Tests/RxCodeChatKitTests/MCPToolResultViewTests.swift b/Packages/Tests/RxCodeChatKitTests/MCPToolResultViewTests.swift index 813ed06d..a380a1b2 100644 --- a/Packages/Tests/RxCodeChatKitTests/MCPToolResultViewTests.swift +++ b/Packages/Tests/RxCodeChatKitTests/MCPToolResultViewTests.swift @@ -27,7 +27,7 @@ struct MCPToolResultViewTests { try view.inspect().find(ViewType.Button.self).tap() - let detail = MCPToolDetailSheet(toolCall: toolCall) + let detail = ToolCallDetailSheet(toolCall: toolCall) let labels = try detail.inspect().findAll(ViewType.Text.self).compactMap { try? $0.string() } #expect(labels.contains("Call Params")) @@ -38,7 +38,7 @@ struct MCPToolResultViewTests { @Test("MCP detail sheet renders inside a narrow host") func detailSheetRendersInsideNarrowHost() throws { - let detail = MCPToolDetailSheet(toolCall: makeMCPToolCall()) + let detail = ToolCallDetailSheet(toolCall: makeMCPToolCall()) .frame(width: 320, height: 560) ViewHosting.host(view: detail) defer { ViewHosting.expel() } @@ -62,7 +62,7 @@ struct MCPToolResultViewTests { try view.inspect().find(ViewType.Button.self).tap() - let detail = MCPToolDetailSheet(toolCall: toolCall) + let detail = ToolCallDetailSheet(toolCall: toolCall) let labels = try detail.inspect().findAll(ViewType.Text.self).compactMap { try? $0.string() } #expect(labels.contains("Call Params")) #expect(labels.contains("Result")) diff --git a/RxCode/App/AppState+CrossProject.swift b/RxCode/App/AppState+CrossProject.swift index 48cb673f..e314cfc6 100644 --- a/RxCode/App/AppState+CrossProject.swift +++ b/RxCode/App/AppState+CrossProject.swift @@ -933,11 +933,17 @@ extension AppState { // MARK: - Editing File Snapshot Capture - /// Detects Edit/MultiEdit/Write tool_use events and kicks off a detached - /// read of every target file's current on-disk contents. The read result - /// is cached on `state.editingFileSnapshotTasks` keyed by absolute path, - /// and only the FIRST tool_use per (session, path) starts a read — later - /// edits in the same thread keep diffing against the original snapshot. + /// Detects Edit/MultiEdit/Write tool_use events and reads the target + /// file's current contents **synchronously** so the pre-edit snapshot is + /// captured before the CLI starts executing the tool. The result is cached + /// on `state.editingFileSnapshots` keyed by absolute path; only the FIRST + /// tool_use per (session, path) reads — later edits in the same thread + /// keep diffing against the original snapshot. A previous implementation + /// did this read on a detached task, which lost the race for large files + /// and produced an `originalContent` identical to `modifiedContent`, + /// collapsing the diff. Reading synchronously here is safe because we run + /// at content_block_stop / assistant tool_use arrival — the CLI has only + /// just finished emitting the tool_use and has not yet executed it. /// /// Handles both the Claude/Anthropic shape (`file_path` in input) and the /// Codex `changes: [{ path, diff }]` shape. Tools that don't touch files @@ -964,11 +970,8 @@ extension AppState { } } - for path in paths where state.editingFileSnapshotTasks[path] == nil { - let capturedPath = path - state.editingFileSnapshotTasks[path] = Task.detached(priority: .userInitiated) { - try? String(contentsOfFile: capturedPath, encoding: .utf8) - } + for path in paths where state.editingFileSnapshots[path] == nil { + state.editingFileSnapshots[path] = try? String(contentsOfFile: path, encoding: .utf8) } } diff --git a/RxCode/App/AppState+Lifecycle.swift b/RxCode/App/AppState+Lifecycle.swift index e63f5166..1d6daf83 100644 --- a/RxCode/App/AppState+Lifecycle.swift +++ b/RxCode/App/AppState+Lifecycle.swift @@ -170,6 +170,7 @@ extension AppState { // it does not drive thread discovery. allSessionSummaries = threadStore.loadAllSummaries() autoArchiveExpiredSessionsIfNeeded() + await autoDeleteExpiredSessionsIfNeeded() purgeStaleBranchBriefingsIfNeeded() persistedQueues = threadStore.loadAllQueues() diff --git a/RxCode/App/AppState+MobileSnapshots.swift b/RxCode/App/AppState+MobileSnapshots.swift index 4f6eace9..83992fe8 100644 --- a/RxCode/App/AppState+MobileSnapshots.swift +++ b/RxCode/App/AppState+MobileSnapshots.swift @@ -715,7 +715,7 @@ extension AppState { // This Turn: every file edited in the thread session (SwiftData history). let editSummaries = threadStore.fetchFileEdits(sessionId: resolvedID).map { $0.toSummary() } - let turnEdits = await withTaskGroup(of: (Int, SyncFileEdit).self) { group in + let unboundedEdits = await withTaskGroup(of: (Int, SyncFileEdit).self) { group in for (index, summary) in editSummaries.enumerated() { group.addTask { let fullFileDiff = await Self.mobileFullFileDiff( @@ -730,7 +730,9 @@ extension AppState { hunks: summary.hunks.map { SyncEditHunk(oldString: $0.oldString, newString: $0.newString) }, - fullFileDiff: fullFileDiff + fullFileDiff: fullFileDiff, + originalContent: summary.originalContent, + modifiedContent: summary.modifiedContent )) } } @@ -741,6 +743,13 @@ extension AppState { } return ordered.compactMap(\.self) } + // The relay caps each encrypted envelope at 10 MiB. A long thread of + // large-file edits can easily exceed that once every file's full + // before/after snapshot is included, and the oversize send is dropped + // silently — leaving the mobile sheet stuck on "Loading changes…". + // Drop snapshots that would push the reply past a conservative budget; + // mobile falls back to `fullFileDiff` / `hunks` when snapshots are nil. + let turnEdits = Self.applySnapshotBudget(to: unboundedEdits) func reply(ok: Bool, error: String?, uncommitted: [SyncGitChange]) async { await MobileSyncService.shared.send( @@ -788,6 +797,36 @@ extension AppState { await reply(ok: true, error: nil, uncommitted: uncommitted) } + /// Strips per-file `originalContent` / `modifiedContent` once the running + /// total of attached snapshots would push the encoded reply past the + /// relay's 10 MiB envelope cap. Order is preserved so earlier files in the + /// thread keep their snapshot-pair diff; later files fall back to the + /// `fullFileDiff` already attached on each `SyncFileEdit`. + nonisolated private static func applySnapshotBudget(to edits: [SyncFileEdit]) -> [SyncFileEdit] { + // Conservative budget — leaves headroom for hunks, full-file diffs, + // uncommitted git changes, JSON escaping, and base64 envelope overhead. + let totalBudget = 4 * 1024 * 1024 + let perFileCap = 512 * 1024 + var remaining = totalBudget + return edits.map { edit in + let pairSize = (edit.originalContent?.utf8.count ?? 0) + + (edit.modifiedContent?.utf8.count ?? 0) + guard pairSize > 0, pairSize <= perFileCap, pairSize <= remaining else { + return SyncFileEdit( + path: edit.path, + name: edit.name, + containsWrite: edit.containsWrite, + hunks: edit.hunks, + fullFileDiff: edit.fullFileDiff, + originalContent: nil, + modifiedContent: nil + ) + } + remaining -= pairSize + return edit + } + } + nonisolated private static func mobileFullFileDiff( path: String, hunks: [PreviewFile.EditHunk], diff --git a/RxCode/App/AppState+MobileSync.swift b/RxCode/App/AppState+MobileSync.swift index 7436b8b4..02261ac2 100644 --- a/RxCode/App/AppState+MobileSync.swift +++ b/RxCode/App/AppState+MobileSync.swift @@ -492,6 +492,21 @@ extension AppState { return } + if request.operation == .initGit { + if let err = await GitHelper.initRepository(at: project.path) { + await replyBranchOpResult( + request: request, + ok: false, + errorMessage: err, + toHex: fromHex + ) + return + } + await replyBranchOpResult(request: request, ok: true, errorMessage: nil, toHex: fromHex) + scheduleMobileSnapshotBroadcast() + return + } + let trimmed = request.branch.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { await replyBranchOpResult( @@ -514,6 +529,8 @@ extension AppState { case .createNew: try await attachWorktree(branch: trimmed, in: window) updateMobilePendingWorktree(from: window, projectID: project.id) + case .initGit: + break // handled above } } catch { await replyBranchOpResult( diff --git a/RxCode/App/AppState+Stream.swift b/RxCode/App/AppState+Stream.swift index 9cc8fd8f..844421ff 100644 --- a/RxCode/App/AppState+Stream.swift +++ b/RxCode/App/AppState+Stream.swift @@ -95,25 +95,28 @@ extension AppState { } if !editPersistInfos.isEmpty { for info in editPersistInfos { - // Pull the snapshot task created at tool_use time - // (see `captureEditingFileSnapshot`). Persist via - // an awaiting MainActor Task so the original-content - // field reflects the file as it stood before the - // edit ran, instead of post-edit content. - let snapshotTask = state.editingFileSnapshotTasks[info.path] + // Pre-edit snapshot was already read synchronously + // at tool_use time (see `captureEditingFileSnapshot`). + // Re-read the file after tool_result for the post- + // edit snapshot. Together they form the snapshot + // pair the diff view and sidebar counts use. + let snapshot = state.editingFileSnapshots[info.path] ?? nil let pathLocal = info.path let hunksLocal = info.hunks let isWriteLocal = info.isWrite let keyLocal = key Task { @MainActor [weak self] in - let snapshot = await snapshotTask?.value ?? nil + let modified = await Task.detached(priority: .userInitiated) { + try? String(contentsOfFile: pathLocal, encoding: .utf8) + }.value guard let self else { return } self.threadStore.appendFileEdit( sessionId: keyLocal, path: pathLocal, hunks: hunksLocal, containsWrite: isWriteLocal, - originalContent: snapshot + originalContent: snapshot, + modifiedContent: modified ) self.threadFileEditsRevision &+= 1 } diff --git a/RxCode/App/AppState+Worktree.swift b/RxCode/App/AppState+Worktree.swift index 7bfdcf95..b3c81a09 100644 --- a/RxCode/App/AppState+Worktree.swift +++ b/RxCode/App/AppState+Worktree.swift @@ -92,6 +92,48 @@ extension AppState { logger.info("Auto-archived \(archivedIds.count) chats older than \(self.archiveRetentionDays) days") } + /// Apply the auto-delete policy: permanently delete archived, non-pinned + /// chats whose `archivedAt` is older than `deleteRetentionDays`. Threads + /// must be archived first — this never deletes active chats. Runs after + /// `autoArchiveExpiredSessionsIfNeeded` at app launch. + func autoDeleteExpiredSessionsIfNeeded() async { + guard autoDeleteEnabled else { return } + let cutoff = Calendar.current.date( + byAdding: .day, + value: -deleteRetentionDays, + to: Date() + ) ?? Date() + let staleIds = Set(threadStore.staleArchivedIds(olderThan: cutoff)) + guard !staleIds.isEmpty else { return } + + let toDelete = allSessionSummaries.filter { staleIds.contains($0.id) } + for summary in toDelete { + let cwd = summary.worktreePath + ?? projects.first(where: { $0.id == summary.projectId })?.path + do { + try await persistence.deleteSession( + projectId: summary.projectId, + sessionId: summary.id, + origin: summary.origin, + cwd: cwd + ) + } catch { + logger.error("Auto-delete: failed to remove session \(summary.id): \(error.localizedDescription)") + } + } + + allSessionSummaries.removeAll { staleIds.contains($0.id) } + for id in staleIds { + threadStore.delete(id: id) + sessionStates.removeValue(forKey: id) + } + let snapshotIds = staleIds + Task.detached(priority: .utility) { [searchService] in + for id in snapshotIds { await searchService.removeThread(id: id) } + } + logger.info("Auto-deleted \(staleIds.count) archived chats older than \(self.deleteRetentionDays) days") + } + /// Persist a metadata-only edit (title, pin, etc.) routing by session /// origin. cliBacked sessions go to the sidecar; legacy sessions need the /// full message log to be re-saved alongside the change. diff --git a/RxCode/App/AppState.swift b/RxCode/App/AppState.swift index 3e0a8671..72ea22e7 100644 --- a/RxCode/App/AppState.swift +++ b/RxCode/App/AppState.swift @@ -94,15 +94,16 @@ struct SessionStreamState { /// from kicking off duplicate generations on the same session. var titleGenerationTriggered: Bool = false - /// File-content snapshots captured the first time this session's stream sees - /// an Edit/MultiEdit/Write tool_use for a given path. Used by the "This - /// thread" diff inspector so the rendered diff compares (file-before-this- - /// thread-touched-it) vs (file-on-disk-now), instead of trying to reverse- - /// apply hunks against the current file — which breaks when concurrent - /// agents modify the same file. The task is kicked off at tool_use time so - /// the read can race ahead of the actual file write. The persistence layer - /// awaits the task when the matching tool_result lands. - var editingFileSnapshotTasks: [String: Task] = [:] + /// File-content snapshots captured the first time this session's stream + /// sees an Edit/MultiEdit/Write tool_use for a given path. Read + /// synchronously at capture time (content_block_stop / assistant tool_use + /// arrival) so we read the pre-edit state before the CLI executes the + /// tool — large files used to lose the race when the read was async and + /// `originalContent` would end up matching `modifiedContent`. Absence of a + /// key means the path hasn't been touched yet in this session; the value + /// can still be `nil` when the read failed (e.g. file does not exist for + /// a new-file Write). + var editingFileSnapshots: [String: String?] = [:] } enum SummarizationProvider: String, CaseIterable, Identifiable { @@ -382,6 +383,25 @@ final class AppState { } } + /// Auto-delete archived chats whose `archivedAt` is older than this many days. + /// Pinned chats are never auto-deleted. Disabled by default — destructive. + static let defaultDeleteRetentionDays = 30 + + var autoDeleteEnabled: Bool = (UserDefaults.standard.object(forKey: "autoDeleteEnabled") as? Bool) ?? false { + didSet { UserDefaults.standard.set(autoDeleteEnabled, forKey: "autoDeleteEnabled") } + } + + var deleteRetentionDays: Int = (UserDefaults.standard.object(forKey: "deleteRetentionDays") as? Int) ?? AppState.defaultDeleteRetentionDays { + didSet { + let clamped = max(1, min(365, deleteRetentionDays)) + if clamped != deleteRetentionDays { + deleteRetentionDays = clamped + return + } + UserDefaults.standard.set(deleteRetentionDays, forKey: "deleteRetentionDays") + } + } + // MARK: - Attachment Auto-Preview Settings static let autoPreviewSettingsKey = "attachmentAutoPreviewSettings" diff --git a/RxCode/Resources/Localizable.xcstrings b/RxCode/Resources/Localizable.xcstrings index ae005906..7ab788fc 100644 --- a/RxCode/Resources/Localizable.xcstrings +++ b/RxCode/Resources/Localizable.xcstrings @@ -71,52 +71,6 @@ } } }, - "@ File Popup" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "@ File Popup" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "@ 파일 팝업" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "@ 文件弹出框" - } - } - } - }, - "@ File References" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "@ File References" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "@ 파일 참조" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "@ 文件引用" - } - } - } - }, "@%@" : { "localizations" : { "zh-Hans" : { @@ -217,60 +171,21 @@ } }, "%@, in progress" : { - - }, - "%@%%" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@%%" - } - } - } - }, - "%d changed" : { - "extractionState" : "stale", "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%d changed" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%d개 변경됨" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%d 个变更" + "value" : "%@,进行中" } } } }, - "%d files" : { - "extractionState" : "stale", + "%@%%" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%d files" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%d개 파일" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%d 个文件" + "value" : "%@%%" } } } @@ -321,67 +236,60 @@ } } }, - "%lld day%@ of inactivity" : { + "%lld day%@ after archiving" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "%1$lld day%2$@ of inactivity" + "value" : "%1$lld day%2$@ after archiving" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "不活跃 %1$lld 天%2$@" + "value" : "归档后 %1$lld 天%2$@" } } } }, - "%lld files" : { + "%lld day%@ of inactivity" : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$lld day%2$@ of inactivity" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%lld 个文件" + "value" : "不活跃 %1$lld 天%2$@" } } } }, - "%lld of %lld agents" : { + "%lld files" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%1$lld of %2$lld agents" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$lld/%2$lld 个智能体" + "value" : "%lld 个文件" } } } }, - "%lld question(s) pending" : { - "extractionState" : "stale", + "%lld of %lld agents" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "%lld question(s) pending" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대기 중인 질문 %lld개" + "value" : "%1$lld of %2$lld agents" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%lld 个问题待处理" + "value" : "%1$lld/%2$lld 个智能体" } } } @@ -514,13086 +422,6606 @@ } } }, - "5h limit — API usage over the last 5 hours (bar + % + time until reset)" : { - "extractionState" : "stale", + "Absolute or project-relative path. Leave empty to use the project root." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "5h limit — API usage over the last 5 hours (bar + % + time until reset)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "5h 한도 — 최근 5시간 API 사용량 (막대 그래프 + % + 리셋까지 남은 시간)" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "5 小时限制 — 最近 5 小时的 API 使用量(条形图 + 百分比 + 距离重置时间)" + "value" : "绝对路径或项目相对路径。留空则使用项目根目录。" } } } }, - "7d limit — API usage over the last 7 days (bar + % + time until reset)" : { - "extractionState" : "stale", + "Accept" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "7d limit — API usage over the last 7 days (bar + % + time until reset)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "7d 한도 — 최근 7일 API 사용량 (막대 그래프 + % + 리셋까지 남은 시간)" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "7 天限制 — 最近 7 天的 API 使用量(条形图 + 百分比 + 距离重置时间)" + "value" : "接受" } } } }, - "70–89% — caution" : { - "extractionState" : "stale", + "ACP Clients" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "70–89% — caution" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "70–89% — 주의" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "70–89% — 注意" + "value" : "ACP 客户端" } } } }, - "90% or above — critical" : { - "extractionState" : "stale", + "ACP error" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "90% or above — critical" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "90% 이상 — 위험" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "90% 或以上 — 严重" + "value" : "ACP 错误" } } } }, - "A fixed information bar at the bottom of the chat area. It shows the current project path, model, rate limit usage, context window usage, and total response time at a glance." : { - "extractionState" : "stale", + "ACP page" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "A fixed information bar at the bottom of the chat area. It shows the current project path, model, rate limit usage, context window usage, and total response time at a glance." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "채팅 영역 하단에 고정된 정보 바입니다. 현재 프로젝트 경로, 모델, 사용량 한도, 컨텍스트 사용량, 총 응답 시간을 한눈에 확인할 수 있습니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "聊天区域底部的固定信息栏。可一目了然地显示当前项目路径、模型、速率限制用量、上下文窗口用量和总响应时间。" + "value" : "ACP 页面" } } } }, - "A native macOS desktop client for the Claude Code CLI. Use all Claude Code features via a polished GUI without needing a terminal." : { - "extractionState" : "stale", + "Action" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "A native macOS desktop client for the Claude Code CLI. Use all Claude Code features via a polished GUI without needing a terminal." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude Code CLI를 위한 네이티브 macOS 데스크톱 클라이언트입니다. 터미널 없이 세련된 GUI로 Claude Code의 모든 기능을 사용할 수 있습니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Claude Code CLI 的原生 macOS 桌面客户端。无需终端,即可通过精致的图形界面使用 Claude Code 的全部功能。" + "value" : "操作" } } } }, - "A per-project rich text memo editor. Notes are auto-saved after a short pause and persist across sessions. Markdown formatting is supported." : { - "extractionState" : "stale", + "Actions for %@" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "A per-project rich text memo editor. Notes are auto-saved after a short pause and persist across sessions. Markdown formatting is supported." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트별 메모 편집기입니다. 메모는 잠시 후 자동 저장되며 세션을 넘어 유지됩니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "按项目保存的富文本备忘录编辑器。笔记会在短暂停顿后自动保存,并在不同会话间保留。支持 Markdown 格式。" + "value" : "%@ 的操作" } } } }, - "About RxCode" : { - "extractionState" : "stale", + "Add" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "About RxCode" + "value" : "Add" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode 소개" + "value" : "추가" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关于 RxCode" + "value" : "添加" } } } }, - "Absolute or project-relative path. Leave empty to use the project root." : { + "Add a Git repository by URL" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "绝对路径或项目相对路径。留空则使用项目根目录。" + "value" : "通过 URL 添加 Git 仓库" } } } }, - "Accent color palette (Terracotta, Ocean, Forest, Lavender, Midnight, Amber)" : { - "extractionState" : "stale", + "Add a preset (e.g. \"dev\", \"prod\") to configure environment variables." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Accent color palette (Terracotta, Ocean, Forest, Lavender, Midnight, Amber)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "강조 색상 팔레트 (Terracotta, Ocean, Forest, Lavender, Midnight, Amber)" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "强调色调色板(陶土、海洋、森林、薰衣草、午夜、琥珀)" + "value" : "添加预设(例如“dev”“prod”)以配置环境变量。" } } } }, - "Accept" : { + "Add a relay server" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "接受" + "value" : "添加中继服务器" } } } }, - "Accept Edits" : { - "extractionState" : "stale", + "Add a skill catalog from a GitHub repository" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Accept Edits" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "편집 수락" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "接受编辑" + "value" : "从 GitHub 仓库添加技能目录" } } } }, - "ACP Clients" : { + "Add Git Skill Source" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "ACP 客户端" + "value" : "添加 Git 技能来源" } } } }, - "ACP error" : { + "Add Git Source" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "ACP 错误" + "value" : "添加 Git 来源" } } } }, - "ACP page" : { + "Add MCP Server" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "ACP 页面" + "value" : "添加 MCP 服务器" } } } }, - "Action" : { + "Add memory" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "操作" + "value" : "添加记忆" } } } }, - "Actions for %@" : { + "Add Memory" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%@ 的操作" + "value" : "添加记忆" } } } }, - "Add" : { + "Add path to message" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Add" + "value" : "Add path to message" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "추가" + "value" : "메시지에 경로 추가" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加" + "value" : "将路径添加到消息" } } } }, - "Add a Git repository by URL" : { + "Add Preset" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "通过 URL 添加 Git 仓库" + "value" : "添加预设" } } } }, - "Add a preset (e.g. \"dev\", \"prod\") to configure environment variables." : { + "Add Profile" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加预设(例如“dev”“prod”)以配置环境变量。" + "value" : "添加配置" } } } }, - "Add a relay server" : { + "Add Project" : { "localizations" : { - "zh-Hans" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Add Project" + } + }, + "ko" : { "stringUnit" : { "state" : "translated", - "value" : "添加中继服务器" + "value" : "프로젝트 추가" } - } - } - }, - "Add a skill catalog from a GitHub repository" : { - "localizations" : { + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "从 GitHub 仓库添加技能目录" + "value" : "添加项目" } } } }, - "Add Git Skill Source" : { + "Add Relay Server" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加 Git 技能来源" + "value" : "添加中继服务器" } } } }, - "Add Git Source" : { + "Add Repository" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加 Git 来源" + "value" : "添加仓库" } } } }, - "Add MCP Server" : { + "Add server" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加 MCP 服务器" + "value" : "添加服务器" } } } }, - "Add memory" : { + "Add Server" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加记忆" + "value" : "添加服务器" } } } }, - "Add Memory" : { + "Add Source" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加记忆" + "value" : "添加来源" } } } }, - "Add path to message" : { + "Add to projects" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Add path to message" + "value" : "Add to projects" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "메시지에 경로 추가" + "value" : "프로젝트에 추가" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "将路径添加到消息" + "value" : "添加到项目" } } } }, - "Add Preset" : { + "Add tools with MCP" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加预设" + "value" : "使用 MCP 添加工具" } } } }, - "Add Profile" : { + "Add Variable" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加配置" + "value" : "添加变量" } } } }, - "Add Project" : { + "Added" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Add Project" + "value" : "Added" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트 추가" + "value" : "추가됨" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加项目" - } - } - } - }, - "Add Relay Server" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加中继服务器" + "value" : "已添加" } } } }, - "Add Repository" : { + "Agent Availability" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加仓库" + "value" : "智能体可用性" } } } }, - "Add server" : { + "Agent Runtimes" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加服务器" + "value" : "智能体运行时" } } } }, - "Add Server" : { + "All archived chats in the current project will be deleted. This action cannot be undone." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加服务器" + "value" : "当前项目中的所有已归档聊天都将被删除。此操作无法撤销。" } } } }, - "Add Source" : { + "All archived chats will be deleted. This action cannot be undone." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加来源" + "value" : "所有已归档聊天都将被删除。此操作无法撤销。" } } } }, - "Add to projects" : { + "All branches" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add to projects" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트에 추가" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加到项目" + "value" : "所有分支" } } } }, - "Add tools with MCP" : { + "All Chats" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用 MCP 添加工具" + "value" : "所有聊天" } } } }, - "Add Variable" : { + "All saved memories will be removed. This action cannot be undone." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加变量" + "value" : "所有保存的记忆都将被移除。此操作无法撤销。" } } } }, - "Added" : { + "All sessions in the current project will be deleted. This action cannot be undone." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Added" + "value" : "All sessions in the current project will be deleted. This action cannot be undone." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "추가됨" + "value" : "현재 프로젝트의 모든 세션이 삭제됩니다. 이 작업은 되돌릴 수 없습니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已添加" + "value" : "当前项目中的所有会话都将被删除。此操作无法撤销。" } } } }, - "Adding a Project" : { - "extractionState" : "stale", + "All sessions will be deleted. This action cannot be undone." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Adding a Project" + "value" : "All sessions will be deleted. This action cannot be undone." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트 추가" + "value" : "모든 세션이 삭제됩니다. 이 작업은 되돌릴 수 없습니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加项目" + "value" : "所有会话都将被删除。此操作无法撤销。" + } + } + } + }, + "All sync traffic flows through relay servers, end-to-end encrypted. Add relay servers to connect with your mobile devices remotely." : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "所有同步流量都会通过中继服务器,并进行端到端加密。添加中继服务器即可远程连接移动设备。" } } } }, - "Adding a Repository" : { - "extractionState" : "stale", + "Allow" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Adding a Repository" + "value" : "Allow" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "저장소 추가" + "value" : "허용" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加仓库" + "value" : "允许" } } } }, - "Adding a Shortcut" : { - "extractionState" : "stale", + "Allow this tool for the session" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Adding a Shortcut" + "value" : "Allow this tool for the session" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "단축 버튼 추가" + "value" : "이 세션 동안 허용" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "添加快捷按钮" + "value" : "在此会话中允许此工具" } } } }, - "Adjust the font size for the app UI (sidebar, toolbars, labels)" : { - "extractionState" : "stale", + "Always allow this command" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Adjust the font size for the app UI (sidebar, toolbars, labels)" + "value" : "Always allow this command" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "앱 UI(사이드바, 툴바, 레이블)의 폰트 크기를 조절합니다." + "value" : "이 명령 항상 허용" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "调整应用界面字体大小(边栏、工具栏、标签)" + "value" : "始终允许此命令" } } } }, - "Adjust the font size in the chat message area" : { - "extractionState" : "stale", + "API Key" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Adjust the font size in the chat message area" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "채팅 메시지 영역의 폰트 크기를 조절합니다." + "value" : "API 密钥" } - }, + } + } + }, + "API_KEY" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "调整聊天消息区域的字体大小" + "value" : "API_KEY" } } } }, - "Agent Availability" : { + "Apple Foundation Model" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "智能体可用性" + "value" : "Apple Foundation 模型" } } } }, - "Agent Runtimes" : { + "Apply" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "智能体运行时" + "value" : "应用" } } } }, - "AI auto-approves safe operations, prompts only for risky ones (requires Max/Team/Enterprise/API plan + Sonnet/Opus 4.6+)" : { - "extractionState" : "stale", + "Approve to run %@" : { + "comment" : "Notification body when Claude queues a tool approval. %@ is the tool name.", "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "AI auto-approves safe operations, prompts only for risky ones (requires Max/Team/Enterprise/API plan + Sonnet/Opus 4.6+)" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "AI가 안전한 작업은 자동 승인, 위험한 작업만 승인 요청 (Max/Team/Enterprise/API 플랜 + Sonnet/Opus 4.6+ 필요)" + "value" : "批准运行 %@" } - }, + } + } + }, + "Archive" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "AI 自动批准安全操作,仅对有风险的操作提示确认(需要 Max/Team/Enterprise/API 套餐 + Sonnet/Opus 4.6+)" + "value" : "归档" } } } }, - "All" : { - "extractionState" : "stale", + "Archive after" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "All" + "state" : "translated", + "value" : "在此之后归档" } - }, - "ko" : { + } + } + }, + "archived" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "전체" + "value" : "archived" } - }, + } + } + }, + "Archived" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "全部" + "value" : "已归档" } } } }, - "All archived chats in the current project will be deleted. This action cannot be undone." : { + "Args (one per line)" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "当前项目中的所有已归档聊天都将被删除。此操作无法撤销。" + "value" : "参数(每行一个)" } } } }, - "All archived chats will be deleted. This action cannot be undone." : { + "Arguments (optional)" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "所有已归档聊天都将被删除。此操作无法撤销。" + "value" : "参数(可选)" } } } }, - "All branches" : { + "Assistant" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "所有分支" + "value" : "助手" } } } }, - "All Chats" : { + "Assistant has a question" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "所有聊天" + "value" : "助手有一个问题" } } } }, - "All saved memories will be removed. This action cannot be undone." : { + "Assistant has a question%@" : { + "comment" : "Notification title when Claude invokes AskUserQuestion. %@ is replaced with \" — \" or empty string.", "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "所有保存的记忆都将被移除。此操作无法撤销。" + "value" : "助手有一个问题%@" } } } }, - "All sessions in the current project will be deleted. This action cannot be undone." : { + "Authenticate on GitHub" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "All sessions in the current project will be deleted. This action cannot be undone." + "value" : "Authenticate on GitHub" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "현재 프로젝트의 모든 세션이 삭제됩니다. 이 작업은 되돌릴 수 없습니다." + "value" : "GitHub에서 인증" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "当前项目中的所有会话都将被删除。此操作无法撤销。" + "value" : "在 GitHub 上认证" } } } }, - "All sessions will be deleted. This action cannot be undone." : { + "Authentication Code" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "All sessions will be deleted. This action cannot be undone." + "value" : "Authentication Code" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "모든 세션이 삭제됩니다. 이 작업은 되돌릴 수 없습니다." + "value" : "인증 코드" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "所有会话都将被删除。此操作无法撤销。" + "value" : "认证代码" } } } }, - "All sync traffic flows through relay servers, end-to-end encrypted. Add relay servers to connect with your mobile devices remotely." : { + "Auto" : { "localizations" : { - "zh-Hans" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "所有同步流量都会通过中继服务器,并进行端到端加密。添加中继服务器即可远程连接移动设备。" + "state" : "new", + "value" : "Auto" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "자동 모드" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "自动" } } } }, - "Allow" : { + "Auto Effort" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Allow" + "value" : "Auto Effort" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "허용" + "value" : "자동" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "允许" + "value" : "自动强度" } } } }, - "Allow this tool for the session" : { + "Auto-archive inactive chats" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Allow this tool for the session" + "state" : "translated", + "value" : "自动归档不活跃聊天" } - }, - "ko" : { + } + } + }, + "Auto-create memories from completed chats" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "이 세션 동안 허용" + "value" : "从已完成聊天自动创建记忆" } - }, + } + } + }, + "Auto-delete" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在此会话中允许此工具" + "value" : "自动删除" + } + } + } + }, + "Auto-delete archived chats" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "自动删除归档聊天" + } + } + } + }, + "Auto-detected" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "自动检测" } } } }, - "Already added to RxCode" : { - "extractionState" : "stale", + "Auto-preview Attachments" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Already added to RxCode" + "value" : "Auto-preview Attachments" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이미 RxCode에 추가됨" + "value" : "첨부 파일 자동 미리보기" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已添加到 RxCode" + "value" : "自动预览附件" } } } }, - "Always allow this command" : { + "auto.preview.desc" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Always allow this command" + "value" : "When enabled, pasting the following content types automatically creates an attachment preview. When disabled, the content is inserted as plain text." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이 명령 항상 허용" + "value" : "활성화하면 다음 콘텐츠 유형을 붙여넣을 때 자동으로 첨부 파일 미리보기가 생성됩니다. 비활성화하면 일반 텍스트로 삽입됩니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "始终允许此命令" + "value" : "启用后,粘贴以下内容类型时会自动创建附件预览。停用后,内容会作为纯文本插入。" + } + } + } + }, + "Awaiting check" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "等待检查" } } } }, - "Amber" : { - "extractionState" : "stale", + "Back" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Amber" + "value" : "Back" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "앰버" + "value" : "뒤로" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "琥珀" + "value" : "返回" } } } }, - "An embedded zsh terminal that opens at the current project's directory. Use it to run shell commands, inspect files, or manage git — all without leaving the app." : { - "extractionState" : "stale", + "Bash" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "An embedded zsh terminal that opens at the current project's directory. Use it to run shell commands, inspect files, or manage git — all without leaving the app." + "state" : "translated", + "value" : "Bash" } - }, - "ko" : { + } + } + }, + "Branch name" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "현재 프로젝트 디렉토리에서 실행되는 내장 zsh 터미널입니다. 앱을 벗어나지 않고 셸 커맨드 실행, 파일 확인, git 관리 등을 할 수 있습니다." + "value" : "分支名称" } - }, + } + } + }, + "Branch or Ref" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "内置 zsh 终端,会在当前项目目录中打开。可用于运行 shell 命令、查看文件或管理 git,全程无需离开应用。" + "value" : "分支或引用" } } } }, - "Answer" : { - "extractionState" : "stale", + "Briefing" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Answer" + "state" : "translated", + "value" : "简报" } - }, - "ko" : { + } + } + }, + "Briefing rolls recent thread summaries into a branch-focused project update." : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "답변" + "value" : "简报会将最近的对话摘要汇总为面向分支的项目更新。" } - }, + } + } + }, + "Briefings" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "回答" + "value" : "简报" } } } }, - "API Key" : { + "Browse…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "API 密钥" + "value" : "浏览…" } } } }, - "API_KEY" : { + "build" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "API_KEY" + "value" : "build" } } } }, - "Apple Foundation Model" : { - - }, - "Apply" : { + "Build runs `xcodebuild build`. Run builds, then launches the produced .app (macOS) or installs + launches on the selected simulator. Pick the destination from the Run toolbar." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "应用" + "value" : "构建会运行 `xcodebuild build`。Run 会先构建,然后启动生成的 .app(macOS),或在所选模拟器上安装并启动。请从运行工具栏选择目标。" } } } }, - "Approval Options" : { - "extractionState" : "stale", + "Cancel" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Approval Options" + "value" : "Cancel" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "승인 옵션" + "value" : "취소" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "批准选项" + "value" : "取消" } } } }, - "Approve all future requests of this type for the current session" : { - "extractionState" : "stale", + "Check Again" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Approve all future requests of this type for the current session" + "value" : "Check Again" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "현재 세션 동안 이 유형의 모든 요청을 승인" + "value" : "다시 확인" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "批准当前会话中此类型的所有后续请求" + "value" : "重新检查" } } } }, - "Approve this single action" : { - "extractionState" : "stale", + "Check for Updates..." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Approve this single action" + "value" : "Check for Updates..." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이 단일 작업만 승인" + "value" : "업데이트 확인..." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "仅批准此操作" + "value" : "检查更新..." } } } }, - "Approve to run %@" : { - "comment" : "Notification body when Claude queues a tool approval. %@ is the tool name.", + "Check the scheme and container path." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "批准运行 %@" + "value" : "检查 scheme 和容器路径。" } } } }, - "Archive" : { + "Checking..." : { "localizations" : { - "zh-Hans" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Checking..." + } + }, + "ko" : { "stringUnit" : { "state" : "translated", - "value" : "归档" + "value" : "확인 중..." } - } - } - }, - "Archive after" : { - "localizations" : { + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在此之后归档" + "value" : "正在检查..." } } } }, - "archived" : { + "Choose one" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "archived" + "value" : "选择一个" } } } }, - "Archived" : { + "Choose the agent for this thread" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已归档" + "value" : "为此对话选择智能体" } } } }, - "Args (one per line)" : { + "Choose which branches to show briefings for." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "参数(每行一个)" + "value" : "选择要显示简报的分支。" } } } }, - "Arguments (optional)" : { + "Choose…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "参数(可选)" + "value" : "选择…" } } } }, - "Ask" : { - "extractionState" : "stale", + "Claude CLI Installation Check" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Ask" + "value" : "Claude CLI Installation Check" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "권한 요청" + "value" : "Claude CLI 설치 확인" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "询问" + "value" : "Claude CLI 安装检查" } } } }, - "Assistant" : { + "Clear destination — pick again from the toolbar" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "助手" + "value" : "清除目标 — 从工具栏重新选择" } } } }, - "Assistant has a question" : { + "Clear task" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "助手有一个问题" + "value" : "清除任务" } } } }, - "Assistant has a question%@" : { - "comment" : "Notification title when Claude invokes AskUserQuestion. %@ is replaced with \" — \" or empty string.", + "Click + in the toolbar to add one." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "助手有一个问题%@" + "value" : "点击工具栏中的 + 添加一个。" } } } }, - "Attaching Files" : { - "extractionState" : "stale", + "Click + to add one." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Attaching Files" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 첨부" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "附加文件" + "value" : "点击 + 添加一个。" } } } }, - "Authenticate on GitHub" : { + "Click to select · Command-right-click to add or remove · Right-click for Show Diff" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Authenticate on GitHub" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub에서 인증" + "value" : "点击选择 · Command-右键添加或移除 · 右键显示差异" } - }, + } + } + }, + "Client" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 GitHub 上认证" + "value" : "客户端" } } } }, - "Authentication Code" : { + "Clone" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Authentication Code" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "인증 코드" + "value" : "克隆" } - }, + } + } + }, + "Clone & Add" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "认证代码" + "value" : "克隆并添加" } } } }, - "Author" : { - "extractionState" : "stale", + "Close" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Author" + "value" : "Close" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "작성자" + "value" : "닫기" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "作者" + "value" : "关闭" } } } }, - "Auto" : { + "Close — you can answer later from the queue" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "자동 모드" + "value" : "关闭 — 你可以稍后从队列中回答" } - }, + } + } + }, + "Close Terminal" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动" + "value" : "关闭终端" } } } }, - "Auto Effort" : { + "Collapse chats" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto Effort" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "자동" + "value" : "折叠聊天" } - }, + } + } + }, + "command" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动强度" + "value" : "command" } } } }, - "Auto-accepts file edits in the working directory (commands still require approval)" : { - "extractionState" : "stale", + "Command" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Auto-accepts file edits in the working directory (commands still require approval)" + "value" : "Command" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "작업 디렉토리 파일 편집을 자동 수락 (명령어는 여전히 승인 필요)" + "value" : "커맨드" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动接受工作目录中的文件编辑(命令仍需批准)" + "value" : "命令" } } } }, - "Auto-archive inactive chats" : { + "Commands" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动归档不活跃聊天" + "value" : "命令" } } } }, - "Auto-create memories from completed chats" : { + "Commit %@" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "从已完成聊天自动创建记忆" + "value" : "提交 %@" } } } }, - "Auto-detected" : { + "Commit message" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动检测" + "value" : "提交消息" } } } }, - "Auto-preview Attachments" : { + "Configuration" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto-preview Attachments" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "첨부 파일 자동 미리보기" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动预览附件" + "value" : "配置" } } } }, - "Auto-Preview Settings" : { - "extractionState" : "stale", + "Configure Model Context Protocol servers used by Claude Code and Codex." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto-Preview Settings" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "자동 미리보기 설정" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动预览设置" + "value" : "配置 Claude Code 和 Codex 使用的模型上下文协议服务器。" } } } }, - "auto.preview.desc" : { + "Configure org access →" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "When enabled, pasting the following content types automatically creates an attachment preview. When disabled, the content is inserted as plain text." + "value" : "Configure org access →" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "활성화하면 다음 콘텐츠 유형을 붙여넣을 때 자동으로 첨부 파일 미리보기가 생성됩니다. 비활성화하면 일반 텍스트로 삽입됩니다." + "value" : "조직 접근 설정 →" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "启用后,粘贴以下内容类型时会自动创建附件预览。停用后,内容会作为纯文本插入。" + "value" : "配置组织访问权限 →" } } } }, - "Autocomplete command" : { - "extractionState" : "stale", + "Connect GitHub" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Autocomplete command" + "value" : "Connect GitHub" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "커맨드 자동 완성" + "value" : "GitHub 연결" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动补全命令" + "value" : "连接 GitHub" } } } }, - "Autocomplete slash command / @ file" : { - "extractionState" : "stale", + "Connect GitHub to\nimport repos instantly" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Autocomplete slash command / @ file" + "value" : "Connect GitHub to\nimport repos instantly" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "슬래시 커맨드 / @ 파일 자동 완성" + "value" : "GitHub를 연결하여\n저장소를 바로 가져오세요" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "自动补全斜杠命令 / @ 文件" + "value" : "连接 GitHub\n即可快速导入仓库" } } } }, - "Automatically convert long text (200+ characters) into an attachment chip when pasted" : { - "extractionState" : "stale", + "Connect GitHub to fetch your repo list and add projects with a single click." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Automatically convert long text (200+ characters) into an attachment chip when pasted" + "value" : "Connect GitHub to fetch your repo list and add projects with a single click." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "긴 텍스트(200자 이상) 붙여넣기 시 자동으로 첨부 파일 칩으로 변환합니다." + "value" : "GitHub를 연결하면 저장소 목록을 가져오고 한 번의 클릭으로 프로젝트를 추가할 수 있습니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "粘贴长文本(200+ 个字符)时自动转换为附件标签" + "value" : "连接 GitHub 以获取仓库列表,并一键添加项目。" } } } }, - "Automatically show a preview chip when a file path is pasted" : { - "extractionState" : "stale", + "Connect the mobile companion" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Automatically show a preview chip when a file path is pasted" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 경로 붙여넣기 시 자동으로 미리보기 칩을 표시합니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "粘贴文件路径时自动显示预览标签" + "value" : "连接移动伴侣应用" } } } }, - "Automatically show a preview chip when a URL is pasted" : { - "extractionState" : "stale", + "Connect to a relay server before pairing a device." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Automatically show a preview chip when a URL is pasted" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "URL 붙여넣기 시 자동으로 미리보기 칩을 표시합니다." + "value" : "配对设备前先连接到中继服务器。" } - }, + } + } + }, + "Connect to relay servers to sync with your mobile devices remotely. You can add multiple relays and connect to all of them simultaneously." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "粘贴 URL 时自动显示预览标签" + "value" : "连接到中继服务器,以便与移动设备远程同步。你可以添加多个中继,并同时连接到它们。" } } } }, - "Automatically show a preview chip when image data is pasted" : { - "extractionState" : "stale", + "Connected" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Automatically show a preview chip when image data is pasted" + "value" : "Connected" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이미지 데이터 붙여넣기 시 자동으로 미리보기 칩을 표시합니다." + "value" : "연결됨" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "粘贴图像数据时自动显示预览标签" + "value" : "已连接" } } } }, - "Awaiting check" : { + "Connecting…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "等待检查" + "value" : "正在连接…" } } } }, - "Back" : { + "connection lost" : { + "comment" : "Fallback MCP disconnect detail when no error message is available.", "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Back" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "뒤로" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "返回" + "value" : "连接已断开" } } } }, - "Bash" : { + "Context memories: %lld" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Bash" + "value" : "上下文记忆:%lld" } } } }, - "Before Claude edits files or runs commands, it pauses and asks for your approval. A modal appears showing the tool name and its arguments." : { - "extractionState" : "stale", + "Copied" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Before Claude edits files or runs commands, it pauses and asks for your approval. A modal appears showing the tool name and its arguments." + "value" : "Copied" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "Claude가 파일을 편집하거나 커맨드를 실행하기 전에 잠시 멈추고 승인을 요청합니다. 도구 이름과 인수를 보여주는 모달이 표시됩니다." + "value" : "복사됨" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 Claude 编辑文件或运行命令之前,它会暂停并请求你的批准。弹窗会显示工具名称及其参数。" + "value" : "已复制" } } } }, - "Below 70% — normal" : { - "extractionState" : "stale", + "Copy" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Below 70% — normal" + "value" : "Copy" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "70% 미만 — 정상" + "value" : "복사" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "低于 70% — 正常" + "value" : "复制" } } } }, - "Binary file — preview not available" : { - "extractionState" : "stale", + "Copy briefing text" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Binary file — preview not available" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "바이너리 파일 — 미리보기 불가" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "二进制文件 — 无法预览" + "value" : "复制简报文本" } } } }, - "Bold" : { - "extractionState" : "stale", + "Copy Code" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Bold" + "value" : "Copy Code" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "굵게" + "value" : "코드 복사" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "粗体" + "value" : "复制代码" } } } }, - "Branch name" : { + "Could not load registry. Check your network connection." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "分支名称" + "value" : "无法加载注册表。请检查网络连接。" } } } }, - "Branch or Ref" : { + "Create and checkout" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "分支或引用" + "value" : "创建并检出" } } } }, - "Briefing" : { + "Create and checkout branch" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "简报" + "value" : "创建并检出分支" } } } }, - "Briefing rolls recent thread summaries into a branch-focused project update." : { + "Create new branch…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "简报会将最近的对话摘要汇总为面向分支的项目更新。" + "value" : "创建新分支…" } } } }, - "Briefings" : { + "Creating…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "简报" + "value" : "正在创建…" } } } }, - "Browse and manage Claude Code skills" : { - "extractionState" : "stale", + "Current branch" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Browse and manage Claude Code skills" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Claude Code 스킬을 탐색하고 관리하세요" + "value" : "当前分支" } - }, + } + } + }, + "Custom" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "浏览和管理 Claude Code 技能" + "value" : "自定义" } } } }, - "Browse…" : { + "Custom Sources" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "浏览…" + "value" : "自定义来源" } } } }, - "build" : { + "Custom target" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "build" + "value" : "自定义目标" } } } }, - "Build runs `xcodebuild build`. Run builds, then launches the produced .app (macOS) or installs + launches on the selected simulator. Pick the destination from the Run toolbar." : { + "Custom…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "构建会运行 `xcodebuild build`。Run 会先构建,然后启动生成的 .app(macOS),或在所选模拟器上安装并启动。请从运行工具栏选择目标。" + "value" : "自定义…" } } } }, - "By default, pasting certain content automatically creates a preview chip. You can toggle each category independently in Settings → Message." : { - "extractionState" : "stale", + "Debug" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "By default, pasting certain content automatically creates a preview chip. You can toggle each category independently in Settings → Message." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "기본적으로 특정 콘텐츠를 붙여넣으면 자동으로 미리보기 칩이 생성됩니다. 설정 → 메시지에서 각 카테고리를 개별적으로 토글할 수 있습니다." + "value" : "Debug" } - }, + } + } + }, + "Decision" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "默认情况下,粘贴某些内容会自动创建预览标签。你可以在“设置 → 消息”中分别开关每个类别。" + "value" : "决策" } } } }, - "Bypass" : { - "extractionState" : "stale", + "Default" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Bypass" + "value" : "Default" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "권한 건너뛰기" + "value" : "기본값" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "绕过" + "value" : "默认" } } } }, - "Cancel" : { + "Default Effort Level" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Cancel" + "value" : "Default Effort Level" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "취소" + "value" : "기본 작업량 수준 (Effort Level)" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "取消" + "value" : "默认推理强度" } } } }, - "Category" : { - "extractionState" : "stale", + "Default Model" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Category" + "value" : "Default Model" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "카테고리" + "value" : "기본 모델" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "分类" + "value" : "默认模型" } } } }, - "Change Theme" : { - "extractionState" : "stale", + "Default Permission Mode" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Change Theme" + "value" : "Default Permission Mode" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "테마 변경" + "value" : "기본 권한 모드 (Permission Mode)" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "更改主题" + "value" : "默认权限模式" } } } }, - "Changing the Model" : { - "extractionState" : "stale", + "Delete" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Changing the Model" + "value" : "Delete" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "모델 변경" + "value" : "삭제" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "更改模型" + "value" : "删除" } } } }, - "Chat Basics" : { - "extractionState" : "stale", + "Delete \"%@\"?" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Chat Basics" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "채팅 기본" + "value" : "删除“%@”?" } - }, + } + } + }, + "Delete after" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "聊天基础" + "value" : "删除时间" } } } }, - "Chat is disabled when no project is selected." : { - "extractionState" : "stale", + "Delete All" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Chat is disabled when no project is selected." + "value" : "Delete All" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트가 선택되지 않으면 채팅을 사용할 수 없습니다." + "value" : "모두 삭제" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "未选择项目时聊天不可用。" + "value" : "全部删除" } } } }, - "Check Again" : { + "Delete All Archived" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Check Again" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "다시 확인" + "value" : "删除所有已归档" } - }, + } + } + }, + "Delete all memories" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重新检查" + "value" : "删除所有记忆" } } } }, - "Check for Updates..." : { + "Delete All Memories?" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Check for Updates..." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "업데이트 확인..." + "value" : "删除所有记忆?" } - }, + } + } + }, + "Delete memory" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "检查更新..." + "value" : "删除记忆" } } } }, - "Check the scheme and container path." : { + "Delete Memory?" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "检查 scheme 和容器路径。" + "value" : "删除记忆?" } } } }, - "Checking for Updates" : { - "extractionState" : "stale", + "Delete Preset" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Checking for Updates" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "업데이트 확인" + "value" : "删除预设" } - }, + } + } + }, + "Delete Profile" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "检查更新" + "value" : "删除配置" } } } }, - "Checking..." : { + "Delete Project" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Checking..." + "value" : "Delete Project" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "확인 중..." + "value" : "프로젝트 삭제" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "正在检查..." + "value" : "删除项目" } } } }, - "Choose one" : { + "Delete Session" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择一个" + "value" : "删除会话" } } } }, - "Choose RxCode → Settings from the menu bar or press ⌘, to open the Settings window. Settings are organized into four tabs: General, Message, Slash Commands, and Shortcuts." : { - "extractionState" : "stale", + "Deny" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Choose RxCode → Settings from the menu bar or press ⌘, to open the Settings window. Settings are organized into four tabs: General, Message, Slash Commands, and Shortcuts." + "value" : "Deny" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "메뉴 막대에서 RxCode → 설정을 선택하거나 ⌘,를 눌러 설정 창을 엽니다. 설정은 일반, 메시지, 슬래시 커맨드, 단축키 네 개의 탭으로 구성되어 있습니다." + "value" : "거부" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "从菜单栏选择“RxCode → 设置”,或按 ⌘, 打开设置窗口。设置分为四个标签页:通用、消息、斜杠命令和快捷按钮。" + "value" : "拒绝" } } } }, - "Choose RxCode → Settings from the menu bar or press ⌘, to open the Settings window. Settings are organized into three tabs: General, Slash Commands, and Shortcuts." : { - "extractionState" : "stale", + "Destination" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Choose RxCode → Settings from the menu bar or press ⌘, to open the Settings window. Settings are organized into three tabs: General, Slash Commands, and Shortcuts." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "从菜单栏选择“RxCode → 设置”,或按 ⌘, 打开设置窗口。设置分为三个标签页:通用、斜杠命令和快捷按钮。" + "value" : "目标" } } } }, - "Choose the agent for this thread" : { + "dev / prod / beta" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "为此对话选择智能体" + "value" : "dev / prod / beta" } } } }, - "Choose which branches to show briefings for." : { + "Device name" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择要显示简报的分支。" + "value" : "设备名称" } } } }, - "Choose…" : { + "Disable globally" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择…" + "value" : "全局禁用" } } } }, - "Claude CLI Installation Check" : { + "Disabled" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Claude CLI Installation Check" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude CLI 설치 확인" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Claude CLI 安装检查" + "value" : "已禁用" } } } }, - "Claude CLI not found" : { - "extractionState" : "stale", + "Disconnected" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Claude CLI not found" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude CLI를 찾을 수 없습니다" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "未找到 Claude CLI" + "value" : "已断开连接" } } } }, - "Claude Code" : { - "extractionState" : "stale", + "Display name" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Claude Code" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude Code" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Claude Code" + "value" : "显示名称" } } } }, - "Claude Code Terminal" : { - "extractionState" : "stale", + "Don't see your org repos?" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Claude Code Terminal" + "value" : "Don't see your org repos?" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "Claude Code 터미널" + "value" : "조직 저장소가 보이지 않나요?" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Claude Code 终端" + "value" : "没有看到组织仓库?" } } } }, - "Claude default — warm orange-red" : { - "extractionState" : "stale", + "Don't see your org repos? →" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Claude default — warm orange-red" + "value" : "Don't see your org repos? →" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "Claude 기본값 — 따뜻한 주황빛 레드" + "value" : "조직 저장소가 보이지 않나요? →" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Claude 默认 — 暖橙红" + "value" : "没有看到组织仓库?→" } } } }, - "Claude model used when starting a new session" : { - "extractionState" : "stale", + "Done" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Claude model used when starting a new session" + "value" : "Done" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "새 세션 시작 시 사용할 Claude 모델" + "value" : "완료" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "开始新会话时使用的 Claude 模型" + "value" : "完成" } } } }, - "Clear destination — pick again from the toolbar" : { + "Duplicate Profile" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "清除目标 — 从工具栏重新选择" + "value" : "复制配置" } } } }, - "Clear Memo" : { - "extractionState" : "stale", + "Edit" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Clear Memo" + "value" : "Edit" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "메모 비우기" + "value" : "편집" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "清空备忘录" + "value" : "编辑" } } } }, - "Clear task" : { + "Edit ACP Client" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "清除任务" + "value" : "编辑 ACP 客户端" } } } }, - "Click + in the toolbar to add one." : { + "Edit Configurations…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击工具栏中的 + 添加一个。" + "value" : "编辑配置…" } } } }, - "Click + to add one." : { + "Edit memory" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击 + 添加一个。" + "value" : "编辑记忆" } } } }, - "Click a plugin to view its details, then press Install. An interactive terminal popup opens and runs the install command automatically." : { - "extractionState" : "stale", + "Edit Memory" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click a plugin to view its details, then press Install. An interactive terminal popup opens and runs the install command automatically." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "플러그인을 클릭하여 상세 정보를 확인한 후 설치 버튼을 누르세요. 대화형 터미널 팝업이 열리고 설치 커맨드가 자동으로 실행됩니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击插件查看详情,然后按“安装”。交互式终端弹窗会打开并自动运行安装命令。" + "value" : "编辑记忆" } } } }, - "Click any file in the Files tab to preview it with syntax highlighting. Press the pencil button to enter edit mode and modify the file directly." : { - "extractionState" : "stale", + "Edit Relay Server" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click any file in the Files tab to preview it with syntax highlighting. Press the pencil button to enter edit mode and modify the file directly." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "파일 탭에서 파일을 클릭하면 구문 강조와 함께 미리 볼 수 있습니다. 연필 버튼을 눌러 편집 모드로 전환하고 파일을 직접 수정할 수 있습니다." + "value" : "编辑中继服务器" } - }, + } + } + }, + "Effort level: %@" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在“文件”标签页点击任意文件即可用语法高亮预览。按铅笔按钮进入编辑模式并直接修改文件。" + "value" : "推理强度:%@" } } } }, - "Click the / button in the toolbar, or open Settings → Slash Commands to add, edit, delete, or disable custom commands. Built-in commands can be edited and enabled or disabled in the app." : { - "extractionState" : "stale", + "Effort Picker" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Click the / button in the toolbar, or open Settings → Slash Commands to add, edit, delete, or disable custom commands. Built-in commands can be edited and enabled or disabled in the app." + "value" : "Effort Picker" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "툴바의 / 버튼을 클릭하거나 설정 → 슬래시 커맨드를 열어 커스텀 커맨드를 추가, 편집, 삭제 또는 비활성화할 수 있습니다. 기본 커맨드는 앱 안에서 내용 편집과 활성화/비활성화를 할 수 있습니다." + "value" : "작업량" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击工具栏中的 / 按钮,或打开“设置 → 斜杠命令”以添加、编辑、删除或禁用自定义命令。内置命令也可以在应用中编辑、启用或禁用。" + "value" : "推理强度选择器" } } } }, - "Click the + button at the top of the sidebar or drag a folder from Finder. Claude Code uses that folder as its working directory." : { - "extractionState" : "stale", + "Empty Bash Configuration" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click the + button at the top of the sidebar or drag a folder from Finder. Claude Code uses that folder as its working directory." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사이드바 상단의 + 버튼을 클릭하거나 Finder에서 폴더를 드래그하세요. Claude Code는 해당 폴더를 작업 디렉토리로 사용합니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击边栏顶部的 + 按钮,或从 Finder 拖入文件夹。Claude Code 会将该文件夹用作工作目录。" + "value" : "空 Bash 配置" } } } }, - "Click the ⚡ button in the toolbar to open the Shortcut Manager, or press the + button on the right side of the shortcut bar. You can set a name, message/command, icon, and color." : { - "extractionState" : "stale", + "Empty Make Configuration" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click the ⚡ button in the toolbar to open the Shortcut Manager, or press the + button on the right side of the shortcut bar. You can set a name, message/command, icon, and color." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "툴바의 ⚡ 버튼을 클릭하여 단축 버튼 관리자를 열거나, 단축 버튼 바 오른쪽의 + 버튼을 누르세요. 이름, 메시지/커맨드, 아이콘, 색상을 설정할 수 있습니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击工具栏中的 ⚡ 按钮打开快捷按钮管理器,或按快捷按钮栏右侧的 + 按钮。你可以设置名称、消息/命令、图标和颜色。" + "value" : "空 Make 配置" } } } }, - "Click the brain icon (🧠) in the toolbar to browse the MCP plugin catalog published on Anthropic's GitHub. Plugins can be filtered by category or searched by name, description, or author." : { - "extractionState" : "stale", + "Empty Xcode Configuration" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click the brain icon (🧠) in the toolbar to browse the MCP plugin catalog published on Anthropic's GitHub. Plugins can be filtered by category or searched by name, description, or author." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "툴바의 🧠 아이콘을 클릭하면 Anthropic GitHub에 게시된 MCP 플러그인 카탈로그를 탐색할 수 있습니다. 카테고리별 필터링 또는 이름, 설명, 작성자로 검색이 가능합니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击工具栏中的大脑图标(🧠)浏览 Anthropic GitHub 上发布的 MCP 插件目录。可按类别筛选插件,或按名称、描述、作者搜索。" + "value" : "空 Xcode 配置" } } } }, - "Click the clip icon to the left of the input field, or drag and drop files onto the input field. When dragging, the input field border highlights in the accent color to show the drop zone." : { - "extractionState" : "stale", + "Enable Focus Mode" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Click the clip icon to the left of the input field, or drag and drop files onto the input field. When dragging, the input field border highlights in the accent color to show the drop zone." + "value" : "Enable Focus Mode" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "입력창 왼쪽의 클립 아이콘을 클릭하거나 파일을 입력창으로 드래그하세요. 드래그 중에는 입력창 테두리가 강조 색상으로 표시됩니다." + "value" : "집중 모드 활성화" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击输入框左侧的回形针图标,或将文件拖放到输入框。拖动时,输入框边框会以强调色高亮显示投放区域。" + "value" : "启用专注模式" } } } }, - "Click the GitHub Mark button at the top of the sidebar to open the GitHub panel. After connecting your GitHub account, your repositories are listed and can be added to RxCode with one click." : { - "extractionState" : "stale", + "Enable globally" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click the GitHub Mark button at the top of the sidebar to open the GitHub panel. After connecting your GitHub account, your repositories are listed and can be added to RxCode with one click." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사이드바 상단의 GitHub 마크 버튼을 클릭하여 GitHub 패널을 열어보세요. GitHub 계정을 연결하면 저장소 목록이 표시되고 한 번의 클릭으로 RxCode에 추가할 수 있습니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击边栏顶部的 GitHub 标记按钮打开 GitHub 面板。连接 GitHub 账号后,你的仓库会列出,并可一键添加到 RxCode。" + "value" : "全局启用" } } } }, - "Click the sidebar.trailing (⊟) button at the top right of the toolbar to toggle the inspector panel. The panel docks to the right side of the window and contains two tabs: Terminal and Memo." : { - "extractionState" : "stale", + "Enable Memory" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Click the sidebar.trailing (⊟) button at the top right of the toolbar to toggle the inspector panel. The panel docks to the right side of the window and contains two tabs: Terminal and Memo." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "툴바 오른쪽 상단의 ⊟ 버튼을 클릭하여 인스펙터 패널을 열고 닫습니다. 패널은 창 오른쪽에 고정되며 터미널과 메모 탭을 포함합니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击工具栏右上角的 sidebar.trailing(⊟)按钮切换检查器面板。面板停靠在窗口右侧,包含“终端”和“备忘录”两个标签页。" + "value" : "启用记忆" } } } }, - "Click to select · Command-right-click to add or remove · Right-click for Show Diff" : { + "Enter a new name for this device." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击选择 · Command-右键添加或移除 · 右键显示差异" + "value" : "输入此设备的新名称。" } } } }, - "Client" : { + "Enter a valid ws:// or wss:// URL." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "客户端" + "value" : "请输入有效的 ws:// 或 wss:// URL。" } } } }, - "Clipboard Detection" : { - "extractionState" : "stale", + "Env File" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Clipboard Detection" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "클립보드 감지" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "剪贴板检测" + "value" : "环境文件" } } } }, - "Clone" : { + "Environment" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "克隆" + "value" : "环境" } } } }, - "Clone & Add" : { + "Environments" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "克隆并添加" + "value" : "环境" } } } }, - "Close" : { + "Error" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Close" + "value" : "Error" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "닫기" + "value" : "오류" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关闭" + "value" : "错误" } } } }, - "Close — you can answer later from the queue" : { + "esc" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关闭 — 你可以稍后从队列中回答" + "value" : "esc" } } } }, - "Close current window" : { - "extractionState" : "stale", + "exit %d" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Close current window" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 창 닫기" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关闭当前窗口" + "value" : "exit %d" } } } }, - "Close popup" : { - "extractionState" : "stale", + "exit 0" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Close popup" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "팝업 닫기" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关闭弹出框" + "value" : "exit 0" } } } }, - "Close popup / stop streaming" : { - "extractionState" : "stale", + "Expand chats" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Close popup / stop streaming" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "팝업 닫기 / 스트리밍 중지" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关闭弹出框 / 停止流式输出" + "value" : "展开聊天" } } } }, - "Close Terminal" : { + "Expired — generating a new QR code" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "关闭终端" + "value" : "已过期 — 正在生成新的二维码" } } } }, - "Collapse chats" : { + "Extra environment" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "折叠聊天" + "value" : "额外环境" } } } }, - "command" : { + "Fact" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "command" + "value" : "事实" } } } }, - "Command" : { + "Failed" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Command" + "value" : "Failed" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "커맨드" + "value" : "실패" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "命令" + "value" : "失败" } } } }, - "Commands" : { + "Failed to check status" : { "localizations" : { - "zh-Hans" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "命令" + "state" : "new", + "value" : "Failed to check status" } - } - } - }, - "Commit %@" : { - "localizations" : { - "zh-Hans" : { + }, + "ko" : { "stringUnit" : { "state" : "translated", - "value" : "提交 %@" + "value" : "상태 확인 실패" } - } - } - }, - "Commit message" : { - "localizations" : { + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "提交消息" + "value" : "检查状态失败" } } } }, - "Configuration" : { + "Fetch" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "配置" + "value" : "获取" } } } }, - "Configure Model Context Protocol servers used by Claude Code and Codex." : { + "Fetch Models" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "配置 Claude Code 和 Codex 使用的模型上下文协议服务器。" + "value" : "获取模型" } } } }, - "Configure org access →" : { + "Fetch models first" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Configure org access →" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "조직 접근 설정 →" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "配置组织访问权限 →" + "value" : "请先获取模型" } } } }, - "Connect GitHub" : { + "File paths" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Connect GitHub" + "value" : "File paths" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub 연결" + "value" : "파일 경로" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "连接 GitHub" + "value" : "文件路径" } } } }, - "Connect GitHub to\nimport repos instantly" : { + "Files" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Connect GitHub to\nimport repos instantly" + "value" : "Files" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub를 연결하여\n저장소를 바로 가져오세요" + "value" : "파일" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "连接 GitHub\n即可快速导入仓库" + "value" : "文件" } } } }, - "Connect GitHub to fetch your repo list and add projects with a single click." : { + "Focus Mode" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Connect GitHub to fetch your repo list and add projects with a single click." + "value" : "Focus Mode" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub를 연결하면 저장소 목록을 가져오고 한 번의 클릭으로 프로젝트를 추가할 수 있습니다." + "value" : "집중 모드" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "连接 GitHub 以获取仓库列表,并一键添加项目。" - } - } - } - }, - "Connect the mobile companion" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "连接移动伴侣应用" - } - } - } - }, - "Connect to a relay server before pairing a device." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配对设备前先连接到中继服务器。" + "value" : "专注模式" } } } }, - "Connect to relay servers to sync with your mobile devices remotely. You can add multiple relays and connect to all of them simultaneously." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "连接到中继服务器,以便与移动设备远程同步。你可以添加多个中继,并同时连接到它们。" - } - } - } - }, - "Connected" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Connected" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "연결됨" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已连接" - } - } - } - }, - "Connecting…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在连接…" - } - } - } - }, - "connection lost" : { - "comment" : "Fallback MCP disconnect detail when no error message is available.", - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "连接已断开" - } - } - } - }, - "context — context window usage for the current session (bar + %)" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "context — context window usage for the current session (bar + %)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "context — 현재 세션의 컨텍스트 윈도우 사용률 (막대 그래프 + %)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "上下文 — 当前会话的上下文窗口用量(条形图 + 百分比)" - } - } - } - }, - "Context memories: %lld" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "上下文记忆:%lld" - } - } - } - }, - "Convert long text (200+ characters) into an attachment chip" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Convert long text (200+ characters) into an attachment chip" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "긴 텍스트(200자 이상)를 첨부 파일 칩으로 변환합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将长文本(200+ 个字符)转换为附件标签" - } - } - } - }, - "Cool blue" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Cool blue" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "시원한 블루" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "冷蓝色" - } - } - } - }, - "Copied" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copied" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "복사됨" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已复制" - } - } - } - }, - "Copy" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "복사" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制" - } - } - } - }, - "Copy briefing text" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制简报文本" - } - } - } - }, - "Copy Code" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Copy Code" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "코드 복사" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制代码" - } - } - } - }, - "Could not load registry. Check your network connection." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无法加载注册表。请检查网络连接。" - } - } - } - }, - "Create and checkout" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "创建并检出" - } - } - } - }, - "Create and checkout branch" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "创建并检出分支" - } - } - } - }, - "Create new branch…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "创建新分支…" - } - } - } - }, - "Creating…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在创建…" - } - } - } - }, - "Current branch" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "当前分支" - } - } - } - }, - "Custom" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自定义" - } - } - } - }, - "Custom Sources" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自定义来源" - } - } - } - }, - "Custom target" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自定义目标" - } - } - } - }, - "Custom…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自定义…" - } - } - } - }, - "Dark indigo" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Dark indigo" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "어두운 인디고" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "深靛蓝" - } - } - } - }, - "Debug" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Debug" - } - } - } - }, - "Decision" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "决策" - } - } - } - }, - "Dedicated Project Window" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Dedicated Project Window" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "전용 프로젝트 창" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "专用项目窗口" - } - } - } - }, - "Deep green" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Deep green" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "깊은 그린" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "深绿色" - } - } - } - }, - "Default" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Default" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본값" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "默认" - } - } - } - }, - "Default — prompts for approval before file edits and commands" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Default — prompts for approval before file edits and commands" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 모드 — 파일 편집과 명령어 실행 시 승인 요청" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "默认 — 文件编辑和命令执行前提示批准" - } - } - } - }, - "Default Effort Level" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Default Effort Level" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 작업량 수준 (Effort Level)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "默认推理强度" - } - } - } - }, - "Default Model" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Default Model" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 모델" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "默认模型" - } - } - } - }, - "Default Permission Mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Default Permission Mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 권한 모드 (Permission Mode)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "默认权限模式" - } - } - } - }, - "Delete" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Delete" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "삭제" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除" - } - } - } - }, - "Delete — remove the session" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Delete — remove the session" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "삭제 — 세션을 삭제합니다" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除 — 移除会话" - } - } - } - }, - "Delete \"%@\"?" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除“%@”?" - } - } - } - }, - "Delete All" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Delete All" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모두 삭제" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全部删除" - } - } - } - }, - "Delete All Archived" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除所有已归档" - } - } - } - }, - "Delete all memories" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除所有记忆" - } - } - } - }, - "Delete All Memories?" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除所有记忆?" - } - } - } - }, - "Delete memory" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除记忆" - } - } - } - }, - "Delete Memory?" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除记忆?" - } - } - } - }, - "Delete Preset" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除预设" - } - } - } - }, - "Delete Profile" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除配置" - } - } - } - }, - "Delete Project" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Delete Project" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트 삭제" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除项目" - } - } - } - }, - "Delete Session" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "删除会话" - } - } - } - }, - "Deny" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Deny" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "거부" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "拒绝" - } - } - } - }, - "Destination" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "目标" - } - } - } - }, - "dev / prod / beta" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "dev / prod / beta" - } - } - } - }, - "Device name" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设备名称" - } - } - } - }, - "Disable globally" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全局禁用" - } - } - } - }, - "Disabled" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已禁用" - } - } - } - }, - "Disconnected" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已断开连接" - } - } - } - }, - "Display name" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示名称" - } - } - } - }, - "Displayed Items" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Displayed Items" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "표시 항목" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示项" - } - } - } - }, - "Don't see your org repos?" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Don't see your org repos?" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "조직 저장소가 보이지 않나요?" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有看到组织仓库?" - } - } - } - }, - "Don't see your org repos? →" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Don't see your org repos? →" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "조직 저장소가 보이지 않나요? →" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有看到组织仓库?→" - } - } - } - }, - "Done" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Done" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "완료" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "完成" - } - } - } - }, - "Double-click" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Double-click" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "더블클릭" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "双击" - } - } - } - }, - "Double-click a project tab to open it in its own independent window. Each window manages its own sessions independently, allowing you to work on multiple projects at once." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Double-click a project tab to open it in its own independent window. Each window manages its own sessions independently, allowing you to work on multiple projects at once." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트 탭을 더블 클릭하면 독립적인 전용 창에서 열립니다. 각 창은 세션을 독립적으로 관리하므로 여러 프로젝트를 동시에 작업할 수 있습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "双击项目标签页即可在独立窗口中打开。每个窗口独立管理自己的会话,让你可以同时处理多个项目。" - } - } - } - }, - "Duplicate Profile" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "复制配置" - } - } - } - }, - "Each inspector tab has a reset button (the circular arrow at the top right of the panel)." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Each inspector tab has a reset button (the circular arrow at the top right of the panel)." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "각 인스펙터 탭에는 리셋 버튼(패널 오른쪽 상단의 원형 화살표)이 있습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "每个检查器标签页都有一个重置按钮(面板右上角的圆形箭头)。" - } - } - } - }, - "Each permission request offers three choices." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Each permission request offers three choices." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "각 권한 요청은 세 가지 선택지를 제공합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "每个权限请求提供三个选项。" - } - } - } - }, - "Edit" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Edit" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "편집" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑" - } - } - } - }, - "Edit ACP Client" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑 ACP 客户端" - } - } - } - }, - "Edit Configurations…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑配置…" - } - } - } - }, - "Edit memory" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑记忆" - } - } - } - }, - "Edit Memory" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑记忆" - } - } - } - }, - "Edit Relay Server" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "编辑中继服务器" - } - } - } - }, - "Effort Level" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Effort Level" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "작업량 수준" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "推理强度" - } - } - } - }, - "Effort level (--effort)" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Effort level (--effort)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "작업량(--effort) 설정" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "推理强度 (--effort)" - } - } - } - }, - "Effort level: %@" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "推理强度:%@" - } - } - } - }, - "Effort Picker" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Effort Picker" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "작업량" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "推理强度选择器" - } - } - } - }, - "effort.desc.auto" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Uses the model's default effort level, chosen automatically based on the active model and plan." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "활성 모델과 플랜에 따라 자동으로 결정되는 모델 기본값을 사용합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "使用模型的默认推理强度,并根据当前模型和套餐自动选择。" - } - } - } - }, - "effort.desc.high" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Balances token usage and intelligence. Good minimum for intelligence-sensitive work." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "토큰 사용량과 지능 수준을 균형 있게 유지합니다. 정확도가 중요한 작업의 최소 권장 수준입니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "平衡 token 用量和智能程度。适合对智能要求较高工作的最低建议。" - } - } - } - }, - "effort.desc.low" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reserve for short, scoped, latency-sensitive tasks that are not intelligence-sensitive." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "지연 시간에 민감하고 복잡하지 않은 짧고 범위가 명확한 작업에 사용하세요." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "保留给简短、范围明确、对延迟敏感且不需要高智能的任务。" - } - } - } - }, - "effort.desc.max" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Deepest reasoning with no token constraint. Current session only. Best for demanding, complex tasks." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "토큰 제한 없이 가장 깊은 추론을 제공합니다. 현재 세션에만 적용됩니다. 복잡하고 까다로운 작업에 적합합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "最深度推理,不限制 token。仅当前会话有效。最适合要求高、复杂的任务。" - } - } - } - }, - "effort.desc.medium" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reduces token usage for cost-sensitive work that can trade off some intelligence." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "일부 정확도를 양보하더라도 토큰 비용을 줄이고 싶을 때 적합합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "为成本敏感型工作减少 token 用量,可接受一定智能折中。" - } - } - } - }, - "effort.desc.xhigh" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Best results for most coding and agentic tasks. Recommended default on Opus 4.7." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대부분의 코딩 및 에이전트 작업에서 최상의 결과를 제공합니다. Opus 4.7의 권장 기본값입니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "适合大多数编码和智能体任务,效果最佳。Opus 4.7 的推荐默认值。" - } - } - } - }, - "Empty Bash Configuration" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "空 Bash 配置" - } - } - } - }, - "Empty Make Configuration" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "空 Make 配置" - } - } - } - }, - "Empty Xcode Configuration" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "空 Xcode 配置" - } - } - } - }, - "Enable a focused chat layout that hides the project tab bar and sidebar controls — useful when you want to concentrate on a single conversation" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Enable a focused chat layout that hides the project tab bar and sidebar controls — useful when you want to concentrate on a single conversation" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트 탭 바와 사이드바 컨트롤을 숨기는 집중 레이아웃을 활성화합니다 — 단일 대화에 집중하고 싶을 때 유용합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用专注聊天布局,隐藏项目标签栏和边栏控件;适合需要专注于单个对话时使用" - } - } - } - }, - "Enable Focus Mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Enable Focus Mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "집중 모드 활성화" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用专注模式" - } - } - } - }, - "Enable globally" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全局启用" - } - } - } - }, - "Enable Memory" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用记忆" - } - } - } - }, - "Enable the \"Run as terminal command\" option to execute the shortcut as a shell command in the inspector terminal instead of sending it as a chat message. The project directory is used as the working directory." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Enable the \"Run as terminal command\" option to execute the shortcut as a shell command in the inspector terminal instead of sending it as a chat message. The project directory is used as the working directory." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "\"터미널 커맨드로 실행\" 옵션을 활성화하면 채팅 메시지 대신 인스펙터 터미널에서 셸 커맨드로 실행됩니다. 프로젝트 디렉토리가 작업 디렉토리로 사용됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用“作为终端命令运行”选项后,快捷按钮会在检查器终端中作为 shell 命令执行,而不是作为聊天消息发送。项目目录会作为工作目录。" - } - } - } - }, - "Enter a new name for this device." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输入此设备的新名称。" - } - } - } - }, - "Enter a valid ws:// or wss:// URL." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "请输入有效的 ws:// 或 wss:// URL。" - } - } - } - }, - "Env File" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "环境文件" - } - } - } - }, - "Environment" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "环境" - } - } - } - }, - "Environments" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "环境" - } - } - } - }, - "Erase the memo for the current project (cannot be undone)" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Erase the memo for the current project (cannot be undone)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 프로젝트의 메모를 모두 삭제합니다 (되돌릴 수 없음)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "清除当前项目的备忘录(无法撤销)" - } - } - } - }, - "Error" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Error" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "오류" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "错误" - } - } - } - }, - "esc" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "esc" - } - } - } - }, - "Execute command" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Execute command" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 실행" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "执行命令" - } - } - } - }, - "Execute selected command" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Execute selected command" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "선택한 커맨드 실행" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "执行所选命令" - } - } - } - }, - "exit %d" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "exit %d" - } - } - } - }, - "exit 0" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "exit 0" - } - } - } - }, - "Exit edit mode" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Exit edit mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "편집 모드 종료" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "退出编辑模式" - } - } - } - }, - "Expand chats" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "展开聊天" - } - } - } - }, - "Expired — generating a new QR code" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已过期 — 正在生成新的二维码" - } - } - } - }, - "Extra environment" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "额外环境" - } - } - } - }, - "Fact" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "事实" - } - } - } - }, - "Failed" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Failed" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "실패" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "失败" - } - } - } - }, - "Failed to check status" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Failed to check status" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상태 확인 실패" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "检查状态失败" - } - } - } - }, - "Fetch" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "获取" - } - } - } - }, - "Fetch Models" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "获取模型" - } - } - } - }, - "Fetch models first" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "请先获取模型" - } - } - } - }, - "File" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件" - } - } - } - }, - "File & Image Attachments" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File & Image Attachments" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 및 이미지 첨부" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件和图像附件" - } - } - } - }, - "File Inspector" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File Inspector" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 인스펙터" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件检查器" - } - } - } - }, - "File is too large (>1MB)" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File is too large (>1MB)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일이 너무 큽니다 (>1MB)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件太大(>1MB)" - } - } - } - }, - "File path → attached as a file" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File path → attached as a file" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 경로 → 파일로 첨부" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件路径 → 作为文件附加" - } - } - } - }, - "File paths" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "File paths" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 경로" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件路径" - } - } - } - }, - "Files" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Files" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件" - } - } - } - }, - "Files larger than 1 MB cannot be previewed." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Files larger than 1 MB cannot be previewed." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "1 MB를 초과하는 파일은 미리볼 수 없습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "大于 1 MB 的文件无法预览。" - } - } - } - }, - "Files tab + activate search" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Files tab + activate search" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 탭 + 검색 활성화" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "文件标签页 + 激活搜索" - } - } - } - }, - "Focus Mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Focus Mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "집중 모드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "专注模式" - } - } - } - }, - "focus.mode.desc" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Hide streaming bubbles and show only completed responses in history." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "스트리밍 중 메시지 버블을 숨기고, 완료된 응답만 히스토리에 표시합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "隐藏流式输出气泡,只在历史记录中显示已完成的回复。" - } - } - } - }, - "Font Size" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Font Size" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "폰트 크기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "字体大小" - } - } - } - }, - "font.size.hint" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Adjust interface and message font sizes independently." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인터페이스와 메시지 폰트 크기를 각각 조절합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "分别调整界面和消息字体大小。" - } - } - } - }, - "Force off" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "强制关闭" - } - } - } - }, - "Force on" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "强制开启" - } - } - } - }, - "Forest" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Forest" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "포레스트" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "森林" - } - } - } - }, - "from %@" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "来自 %@" - } - } - } - }, - "General" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "General" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "일반" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "通用" - } - } - } - }, - "General Tab" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "General Tab" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "일반 탭" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "通用标签页" - } - } - } - }, - "Generate" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "生成" - } - } - } - }, - "Generate a commit message from the staged diff" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "根据已暂存差异生成提交消息" - } - } - } - }, - "Get Started" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Get Started" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "시작하기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "开始使用" - } - } - } - }, - "Git Repositories" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Git 仓库" - } - } - } - }, - "Git Status" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Git Status" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Git 상태" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Git 状态" - } - } - } - }, - "Git URL" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Git URL" - } - } - } - }, - "GitHub" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "GitHub" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub" - } - } - } - }, - "GitHub Integration" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "GitHub Integration" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub 연동" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub 集成" - } - } - } - }, - "GitHub Repository" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub 仓库" - } - } - } - }, - "Global" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全局" - } - } - } - }, - "Global default" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全局默认" - } - } - } - }, - "Global default plus per-project override" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全局默认值加项目级覆盖" - } - } - } - }, - "Global Shortcuts" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Global Shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "전체 단축키" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "全局快捷键" - } - } - } - }, - "Go to Files tab" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Go to Files tab" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 탭으로 이동" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "转到文件标签页" - } - } - } - }, - "Go to History tab" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Go to History tab" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기록 탭으로 이동" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "转到历史标签页" - } - } - } - }, - "Headers" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "标头" - } - } - } - }, - "Heading levels (# / ## / ###)" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Heading levels (# / ## / ###)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "제목 수준 (# / ## / ###)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "标题级别(# / ## / ###)" - } - } - } - }, - "Hidden Files" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Hidden Files" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "숨김 파일" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "隐藏文件" - } - } - } - }, - "Hide details" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "隐藏详情" - } - } - } - }, - "Hide Hidden Files" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "隐藏隐藏文件" - } - } - } - }, - "Hide more" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "隐藏更多" - } - } - } - }, - "High" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "High" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "높음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "高" - } - } - } - }, - "History" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "History" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기록" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "历史" - } - } - } - }, - "History Management" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "History Management" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기록 관리" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "历史管理" - } - } - } - }, - "History tab: shows previous conversations\nFiles tab: browse the project file tree" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "History tab: shows previous conversations\nFiles tab: browse the project file tree" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기록 탭: 이전 대화 표시\n파일 탭: 프로젝트 파일 트리 탐색" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "历史标签页:显示之前的对话\n文件标签页:浏览项目文件树" - } - } - } - }, - "Homepage" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Homepage" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "홈페이지" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "主页" - } - } - } - }, - "How to Use" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "How to Use" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사용 방법" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "使用方法" - } - } - } - }, - "https://example.com/mcp" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://example.com/mcp" - } - } - } - }, - "https://github.com/owner/repo" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://github.com/owner/repo" - } - } - } - }, - "https://github.com/owner/repo.git or git@github.com:owner/repo.git" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "https://github.com/owner/repo.git or git@github.com:owner/repo.git" - } - } - } - }, - "If no action is taken, the request is automatically denied after 5 minutes. Press Return to Allow, or Escape to Deny." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "If no action is taken, the request is automatically denied after 5 minutes. Press Return to Allow, or Escape to Deny." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "5분 안에 응답이 없으면 요청이 자동으로 거부됩니다. Return으로 허용, Escape로 거부할 수 있습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "如果不采取任何操作,请求会在 5 分钟后自动拒绝。按 Return 允许,或按 Escape 拒绝。" - } - } - } - }, - "Image data (PNG/TIFF) → attached as an image" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Image data (PNG/TIFF) → attached as an image" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이미지 데이터(PNG/TIFF) → 이미지로 첨부" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "图像数据(PNG/TIFF)→ 作为图像附加" - } - } - } - }, - "Images" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Images" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이미지" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "图片" - } - } - } - }, - "In a dedicated project window, only the project name is shown — there are no project tabs." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "In a dedicated project window, only the project name is shown — there are no project tabs." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "전용 프로젝트 창에서는 프로젝트 이름만 표시되며 프로젝트 탭은 없습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在专用项目窗口中,只显示项目名称,不显示项目标签页。" - } - } - } - }, - "In progress" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "进行中" - } - } - } - }, - "Inactive chats are moved to the archive automatically. Pinned chats are never auto-archived." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "不活跃聊天会自动移入归档。固定的聊天永远不会自动归档。" - } - } - } - }, - "Include relevant memories in agent context" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在智能体上下文中包含相关记忆" - } - } - } - }, - "Inherit global default" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "继承全局默认值" - } - } - } - }, - "Inline code" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Inline code" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인라인 코드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "行内代码" - } - } - } - }, - "Input" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Input" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输入" - } - } - } - }, - "Input Field Shortcuts" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Input Field Shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력창 단축키" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输入框快捷键" - } - } - } - }, - "Insert file path" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Insert file path" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 경로 삽입" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "插入文件路径" - } - } - } - }, - "Insert file path into message" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Insert file path into message" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지에 파일 경로 삽입" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "将文件路径插入消息" - } - } - } - }, - "Insert line break" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Insert line break" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "줄 바꿈 삽입" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "插入换行" - } - } - } - }, - "Insert link" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Insert link" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "링크 삽입" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "插入链接" - } - } - } - }, - "Inspector Panel" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Inspector Panel" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인스펙터 패널" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "检查器面板" - } - } - } - }, - "Install" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Install" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "安装" - } - } - } - }, - "Install ACP agents" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "安装 ACP 智能体" - } - } - } - }, - "Install Command" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Install Command" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치 커맨드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "安装命令" - } - } - } - }, - "Install command:" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Install command:" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치 커맨드:" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "安装命令:" - } - } - } - }, - "Installed" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Installed" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치됨" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已安装" - } - } - } - }, - "Installed — %@" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Installed — %@" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치됨 — %@" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已安装 — %@" - } - } - } - }, - "Installed skills are managed by RxCode, sourced from OpenAI Agent Skills and compatible catalogs, and enabled for Claude Code, Codex, and ACP agents where supported." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已安装技能由 RxCode 管理,来源于 OpenAI Agent Skills 和兼容目录,并会在支持的 Claude Code、Codex 和 ACP 智能体中启用。" - } - } - } - }, - "Installing Plugins" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Installing Plugins" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "플러그인 설치" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "安装插件" - } - } - } - }, - "Installing..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Installing..." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치 중..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在安装..." - } - } - } - }, - "Installing…" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Installing…" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설치 중…" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在安装…" - } - } - } - }, - "Interactive Commands" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interactive Commands" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인터랙티브 커맨드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "交互式命令" - } - } - } - }, - "Interactive Terminal Popup" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interactive Terminal Popup" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "대화형 터미널 팝업" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "交互式终端弹窗" - } - } - } - }, - "Interface" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Interface" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인터페이스" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "界面" - } - } - } - }, - "Italic" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Italic" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기울임꼴" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "斜体" - } - } - } - }, - "Items are shown left to right in the status line." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Items are shown left to right in the status line." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상태 표시줄 왼쪽부터 오른쪽 순서로 다음 정보가 표시됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "状态行中的项目从左到右显示。" - } - } - } - }, - "JSON import/export backs up or shares custom commands only. Built-in commands in imported files are ignored." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "JSON import/export backs up or shares custom commands only. Built-in commands in imported files are ignored." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "JSON 가져오기/내보내기는 커스텀 커맨드만 백업하거나 공유합니다. 가져온 파일의 기본 커맨드는 무시됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "JSON 导入/导出只会备份或共享自定义命令。导入文件中的内置命令会被忽略。" - } - } - } - }, - "JSON import/export is supported for backing up or sharing your shortcut set." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "JSON import/export is supported for backing up or sharing your shortcut set." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축 버튼 세트를 백업하거나 공유하기 위한 JSON 가져오기/내보내기를 지원합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "支持通过 JSON 导入/导出来备份或共享快捷按钮集。" - } - } - } - }, - "Keep summaries on the thread model, or route titles and briefings through an OpenAI-compatible endpoint." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "可使用对话模型生成摘要,或通过 OpenAI 兼容端点处理标题和简报。" - } - } - } - }, - "KEY" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "KEY" - } - } - } - }, - "Keyboard Shortcuts" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Keyboard Shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "键盘快捷键" - } - } - } - }, - "Kind" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "类型" - } - } - } - }, - "Lavender" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Lavender" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "라벤더" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "薰衣草" - } - } - } - }, - "Line break" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Line break" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "줄 바꿈" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "换行" - } - } - } - }, - "Live channel only" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "仅实时通道" - } - } - } - }, - "Load from .env file" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "从 .env 文件加载" - } - } - } - }, - "Loading catalog..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Loading catalog..." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "카탈로그 불러오는 중..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载目录..." - } - } - } - }, - "Loading destinations…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载目标…" - } - } - } - }, - "Loading registry…" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载注册表…" - } - } - } - }, - "Loading repos..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Loading repos..." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "저장소 불러오는 중..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载仓库..." - } - } - } - }, - "loading..." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "loading..." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "불러오는 중..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载..." - } - } - } - }, - "Loading..." : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Loading..." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "불러오는 중..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "正在加载..." - } - } - } - }, - "Local" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Local" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "로컬" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "本地" - } - } - } - }, - "Local on-device search · archived threads included" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "本地设备端搜索 · 包含已归档对话" - } - } - } - }, - "Long text (>2 KB) → converted to a text attachment" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Long text (>2 KB) → converted to a text attachment" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "장문 텍스트(>2 KB) → 텍스트 첨부 파일로 변환" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "长文本(>2 KB)→ 转换为文本附件" - } - } - } - }, - "Long text (200+ characters)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Long text (200+ characters)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "긴 텍스트 (200자 이상)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "长文本(200 字符以上)" - } - } - } - }, - "Low" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Low" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "낮음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "低" - } - } - } - }, - "main" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "main" - } - } - } - }, - "Main Layout" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Main Layout" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "기본 레이아웃" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "主布局" - } - } - } - }, - "Make" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Make" - } - } - } - }, - "Makefile" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Makefile" - } - } - } - }, - "Makefile (optional)" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Makefile(可选)" - } - } - } - }, - "Malformed question payload" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "问题载荷格式错误" - } - } - } - }, - "Manage" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理" - } - } - } - }, - "Manage agents that speak the Agent Client Protocol. Detected from agentclientprotocol.com." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理使用 Agent Client Protocol 的智能体。从 agentclientprotocol.com 检测。" - } - } - } - }, - "Manage GitHub Repos" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage GitHub Repos" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "GitHub 저장소 관리" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理 GitHub 仓库" - } - } - } - }, - "Manage MCP servers once in RxCode, then enable or disable them globally or per project." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在 RxCode 中统一管理 MCP 服务器,然后全局或按项目启用/禁用。" - } - } - } - }, - "Manage Shortcuts" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage Shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키 관리" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理快捷方式" - } - } - } - }, - "Manage Slash Commands" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Manage Slash Commands" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드 관리" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理斜杠命令" - } - } - } - }, - "Managing Commands" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Managing Commands" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 관리" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理命令" - } - } - } - }, - "Managing Shortcuts" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Managing Shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축 버튼 관리" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理快捷按钮" - } - } - } - }, - "Manual key/value pairs" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "手动键/值对" - } - } - } - }, - "Market" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Market" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "마켓" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "市场" - } - } - } - }, - "Matched on title" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "按标题匹配" - } - } - } - }, - "Max" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Max" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "최대" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "最大" - } - } - } - }, - "MCP" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "MCP" - } - } - } - }, - "MCP error" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "MCP 错误" - } - } - } - }, - "MCP server disconnected" : { - "comment" : "Notification title when an MCP server transitions from connected to failed.", - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "MCP 服务器已断开连接" - } - } - } - }, - "MCP Servers" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "MCP 服务器" - } - } - } - }, - "Medium" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Medium" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "보통" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "中" - } - } - } - }, - "Memo" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Memo" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메모" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "备忘" - } - } - } - }, - "Memo Tab" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Memo Tab" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메모 탭" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "备忘录标签页" - } - } - } - }, - "Memory" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "记忆" - } - } - } - }, - "Memory History" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "记忆历史" - } - } - } - }, - "Menu Bar" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "菜单栏" - } - } - } - }, - "Message" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Message" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "消息" - } - } - } - }, - "Message Queue" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Message Queue" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지 큐" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "消息队列" - } - } - } - }, - "Message Tab" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Message Tab" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지 탭" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "消息标签页" - } - } - } - }, - "Messages" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Messages" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "消息" - } - } - } - }, - "Midnight" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Midnight" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "미드나잇" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "午夜" - } - } - } - }, - "Mobile" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "移动端" - } - } - } - }, - "Mobile companion" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "移动伴侣应用" - } - } - } - }, - "Model" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "模型" - } - } - } - }, - "Model — name of the Claude model in use for this session" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Model — name of the Claude model in use for this session" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모델 — 현재 세션에서 사용 중인 Claude 모델 이름" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "模型 — 当前会话使用的 Claude 模型名称" - } - } - } - }, - "Model Picker" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Model Picker" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모델" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "模型选择器" - } - } - } - }, - "Model, permission mode, and effort can also be overridden per session from the toolbar — the chosen value sticks to that session." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Model, permission mode, and effort can also be overridden per session from the toolbar — the chosen value sticks to that session." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모델, 권한 모드, 작업량은 툴바에서 세션별로도 변경할 수 있으며, 선택한 값은 해당 세션에만 적용됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "也可以从工具栏为每个会话单独覆盖模型、权限模式和推理强度;所选值会保留在该会话中。" - } - } - } - }, - "Model: %@ · %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Model: %1$@ · %2$@" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "模型:%1$@ · %2$@" - } - } - } - }, - "model.desc.best" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Most capable available model, currently equivalent to Opus" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "현재 사용 가능한 가장 강력한 모델 (현재 Opus와 동일)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "当前可用的最强模型,目前等同于 Opus" - } - } - } - }, - "model.desc.default" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reverts to the recommended model for your account type" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "계정 유형에 따른 권장 모델로 되돌림" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "恢复为适合你账户类型的推荐模型" - } - } - } - }, - "model.desc.haiku" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Fast and efficient model for simple tasks" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "간단한 작업을 위한 빠르고 효율적인 모델" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "适合简单任务的快速高效模型" - } - } - } - }, - "model.desc.opus" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Latest Opus model for complex reasoning tasks" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "복잡한 추론 작업을 위한 최신 Opus 모델" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "适合复杂推理任务的最新 Opus 模型" - } - } - } - }, - "model.desc.opus1m" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Opus with 1 million token context window for long sessions" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "긴 세션을 위한 100만 토큰 컨텍스트 윈도우 Opus" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "带 100 万 token 上下文窗口的 Opus,适合长会话" - } - } - } - }, - "model.desc.opusplan" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Opus in plan mode, then switches to Sonnet for execution" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Plan Mode에서 Opus 사용 후 실행 시 Sonnet으로 전환" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在计划模式中使用 Opus,执行时切换到 Sonnet" - } - } - } - }, - "model.desc.sonnet" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Latest Sonnet model for daily coding tasks" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "일일 코딩 작업을 위한 최신 Sonnet 모델" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "适合日常编码任务的最新 Sonnet 模型" - } - } - } - }, - "model.desc.sonnet1m" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Sonnet with 1 million token context window for long sessions" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "긴 세션을 위한 100만 토큰 컨텍스트 윈도우 Sonnet" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "带 100 万 token 上下文窗口的 Sonnet,适合长会话" - } - } - } - }, - "Models" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "模型" - } - } - } - }, - "More" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "更多" - } - } - } - }, - "My Relay Server" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "我的中继服务器" - } - } - } - }, - "my-project" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "my-project" - } - } - } - }, - "my-server" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "my-server" - } - } - } - }, - "Name" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "名称" - } - } - } - }, - "New Chat" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "New Chat" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 채팅" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "新建聊天" - } - } - } - }, - "New Chat in %@" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在 %@ 中新建聊天" - } - } - } - }, - "New Terminal" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "新建终端" - } - } - } - }, - "New Terminal (⌘T)" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "新建终端(⌘T)" - } - } - } - }, - "Next" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "下一步" - } - } - } - }, - "Next message / clear input" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Next message / clear input" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "다음 메시지 / 입력 지우기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "下一条消息 / 清空输入" - } - } - } - }, - "No active runs" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有正在运行的任务" - } - } - } - }, - "No agents match “%@”." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有匹配“%@”的智能体。" - } - } - } - }, - "No archived chats" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有已归档聊天" - } - } - } - }, - "No changes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No changes" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "변경사항 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有变更" - } - } - } - }, - "No chat history" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No chat history" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "채팅 기록 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有聊天历史" - } - } - } - }, - "No chats yet" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "还没有聊天" - } - } - } - }, - "No clients installed. Add one from the Registry tab." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未安装客户端。请从“注册表”标签页添加一个。" - } - } - } - }, - "No custom Git sources" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有自定义 Git 来源" - } - } - } - }, - "No custom Git sources added." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "尚未添加自定义 Git 来源。" - } - } - } - }, - "No custom repositories" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有自定义仓库" - } - } - } - }, - "No destinations found" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未找到目标" - } - } - } - }, - "No editors detected" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未检测到编辑器" - } - } - } - }, - "No environment variables defined" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未定义环境变量" - } - } - } - }, - "No local branches" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No local branches" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "로컬 브랜치 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有本地分支" - } - } - } - }, - "No matching memories" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有匹配的记忆" - } - } - } - }, - "No memories" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有记忆" - } - } - } - }, - "No paired devices yet." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "尚未配对设备。" - } - } - } - }, - "No profiles for this project" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "此项目没有配置" - } - } - } - }, - "No profiles yet" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "还没有配置" - } - } - } - }, - "No project" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有项目" - } - } - } - }, - "No projects yet" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "还没有项目" - } - } - } - }, - "No relay servers" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有中继服务器" - } - } - } - }, - "No remote branches" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No remote branches" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "원격 브랜치 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有远程分支" - } - } - } - }, - "No repos found" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No repos found" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "저장소를 찾을 수 없습니다" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未找到仓库" - } - } - } - }, - "No response received" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No response received" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "응답을 받지 못했습니다" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未收到响应" - } - } - } - }, - "No results for '%@'" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No results for '%@'" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "'%@'에 대한 검색 결과 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有“%@”的结果" - } - } - } - }, - "No results found" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No results found" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "검색 결과 없음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未找到结果" - } - } - } - }, - "No servers" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有服务器" - } - } - } - }, - "No summary yet" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "还没有摘要" - } - } - } - }, - "No tasks" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有任务" - } - } - } - }, - "No tools advertised." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未声明任何工具。" - } - } - } - }, - "None" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无" - } - } - } - }, - "Normal mode — permission prompts appear as usual" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Normal mode — permission prompts appear as usual" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "일반 모드 — 권한 요청 팝업이 정상 표시됩니다" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "普通模式 — 权限提示照常显示" - } - } - } - }, - "Not a Git repository" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Not a Git repository" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Git 저장소가 아닙니다" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "不是 Git 仓库" - } - } - } - }, - "Not found" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未找到" - } - } - } - }, - "Not installed" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Not installed" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "미설치" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未安装" - } - } - } - }, - "Notifications" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Notifications" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "알림" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "通知" - } - } - } - }, - "Notify when response completes" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Notify when response completes" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "응답 완료 시 알림" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "回复完成时通知" - } - } - } - }, - "npx" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "npx" - } - } - } - }, - "Ocean" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Ocean" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "오션" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "海洋" - } - } - } - }, - "OK" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "OK" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "확인" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "确定" - } - } - } - }, - "Only enable Skip Permissions on projects you fully trust." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Only enable Skip Permissions on projects you fully trust." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "완전히 신뢰하는 프로젝트에서만 권한 건너뛰기를 활성화하세요." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "仅在你完全信任的项目中启用跳过权限。" - } - } - } - }, - "Only enable Skip Permissions on projects you fully trust. Mode changes take effect from the next message." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Only enable Skip Permissions on projects you fully trust. Mode changes take effect from the next message." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "완전히 신뢰하는 프로젝트에서만 활성화하세요. 모드 변경은 다음 메시지 전송부터 적용됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "仅在你完全信任的项目中启用跳过权限。模式更改会从下一条消息开始生效。" - } - } - } - }, - "Open in External Editor" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在外部编辑器中打开" - } - } - } - }, - "Open in GitHub" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在 GitHub 中打开" - } - } - } - }, - "Open in New Window" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在新窗口中打开" - } - } - } - }, - "Open Project" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开项目" - } - } - } - }, - "Open project branch briefing" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开项目分支简报" - } - } - } - }, - "Open RxCode" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开 RxCode" - } - } - } - }, - "Open RxCode → Check for Updates… to run Sparkle's update check manually. Updates are also checked automatically on launch." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Open RxCode → Check for Updates… to run Sparkle's update check manually. Updates are also checked automatically on launch." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode → 업데이트 확인…을 통해 Sparkle 업데이트 확인을 수동으로 실행할 수 있습니다. 앱 시작 시에도 자동으로 확인됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开“RxCode → 检查更新…”可手动运行 Sparkle 更新检查。启动时也会自动检查更新。" - } - } - } - }, - "Open Settings → Shortcuts to reorder, edit, or delete shortcuts. Shortcut configurations are saved per project." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Open Settings → Shortcuts to reorder, edit, or delete shortcuts. Shortcut configurations are saved per project." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설정 → 단축키를 열어 단축 버튼을 순서 변경, 편집 또는 삭제할 수 있습니다. 설정은 프로젝트별로 저장됩니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开“设置 → 快捷按钮”可重新排序、编辑或删除快捷按钮。快捷按钮配置按项目保存。" - } - } - } - }, - "Open Source" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Open Source" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "오픈 소스" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "开源" - } - } - } - }, - "Open Terminal (⌥-click for window)" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开终端(⌥-点击打开窗口)" - } - } - } - }, - "Open the branch briefing" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开分支简报" - } - } - } - }, - "Open thread" : { - "extractionState" : "stale", - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开对话" - } - } - } - }, - "OpenAI-Compatible Endpoint" : { - - }, - "Opening Settings" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Opening Settings" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "설정 열기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开设置" - } - } - } - }, - "Opening the Inspector Panel" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Opening the Inspector Panel" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "인스펙터 패널 열기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "打开检查器面板" - } - } - } - }, - "Opus 4.6 only" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Opus 4.6 only" - } - } - } - }, - "Other" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "其他" - } - } - } - }, - "Override" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "覆盖" - } - } - } - }, - "Pair a new device" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配对新设备" - } - } - } - }, - "Pair an iPhone or iPad to review threads, answer approvals, and send messages to your desktop agent." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配对 iPhone 或 iPad,以查看对话、响应批准请求,并向桌面智能体发送消息。" - } - } - } - }, - "Pair an iPhone or iPad to view threads, get notifications, and send messages to your desktop agent." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配对 iPhone 或 iPad,以查看对话、接收通知,并向桌面智能体发送消息。" - } - } - } - }, - "Pair new device" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "配对新设备" - } - } - } - }, - "Paired devices" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已配对设备" - } - } - } - }, - "Pasting (⌘V) is smart — RxCode detects what's in the clipboard and handles it automatically." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Pasting (⌘V) is smart — RxCode detects what's in the clipboard and handles it automatically." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "붙여넣기(⌘V)가 스마트합니다 — RxCode가 클립보드 내용을 자동으로 감지하여 처리합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "粘贴(⌘V)是智能的:RxCode 会检测剪贴板内容并自动处理。" - } - } - } - }, - "perm.desc.acceptEdits" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto-approves file edits and common filesystem commands (mkdir, touch, mv, cp). Still prompts for other shell commands." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 편집 및 일반 파일시스템 명령(mkdir, touch, mv, cp)을 자동 승인합니다. 다른 셸 명령은 여전히 확인을 요청합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自动批准文件编辑和常见文件系统命令(mkdir、touch、mv、cp)。其他 shell 命令仍会提示。" - } - } - } - }, - "perm.desc.auto" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Runs without permission prompts. A background classifier reviews each action for safety before it executes." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 확인 없이 실행됩니다. 백그라운드 분류기가 각 작업을 실행 전에 안전 여부를 검토합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无需权限提示即可运行。每个操作执行前,后台分类器会检查其安全性。" - } - } - } - }, - "perm.desc.bypassPermissions" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skips all permission checks and safety gates. Use only in isolated containers or VMs without internet access." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "모든 권한 확인 및 안전 장치를 건너뜁니다. 인터넷이 차단된 컨테이너나 VM 환경에서만 사용하세요." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "跳过所有权限检查和安全门控。仅在无网络的隔离容器或虚拟机中使用。" - } - } - } - }, - "perm.desc.default" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Prompts before each file edit or shell command. Best for sensitive work or getting started." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 편집이나 셸 명령 실행 전마다 확인을 요청합니다. 민감한 작업이나 처음 시작할 때 적합합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "每次文件编辑或 shell 命令前都提示确认。适合敏感工作或初次使用。" - } - } - } - }, - "perm.desc.plan" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Read-only mode. Claude researches and proposes a plan without making any changes. Same prompts as default for other actions." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "읽기 전용 모드입니다. Claude가 변경 없이 코드베이스를 분석하고 계획을 제안합니다. 나머지 작업에는 기본 모드와 동일한 확인을 적용합니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "只读模式。Claude 会研究并提出计划,不会进行更改。其他操作使用与默认模式相同的提示。" - } - } - } - }, - "Permission Mode" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Permission Mode" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 모드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "权限模式" - } - } - } - }, - "Permission mode applied to new sessions" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Permission mode applied to new sessions" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새 세션에 적용될 권한 모드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "应用于新会话的权限模式" - } - } - } - }, - "Permission mode: %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Permission mode: %@" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 모드: %@" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "权限模式:%@" - } - } - } - }, - "Permission needed%@" : { - "comment" : "Notification title when Claude queues a tool approval. %@ is replaced with \" — \" or empty string.", - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "需要权限%@" - } - } - } - }, - "Permission Request" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Permission Request" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 요청" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "权限请求" - } - } - } - }, - "Permission Requests" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Permission Requests" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 요청" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "权限请求" - } - } - } - }, - "Pick a profile in the toolbar and press Run." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "在工具栏中选择配置并按“运行”。" - } - } - } - }, - "Pin" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Pin" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "고정" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "固定" - } - } - } - }, - "Pin / Unpin — pinned sessions stay at the top of the list" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Pin / Unpin — pinned sessions stay at the top of the list" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "고정 / 고정 해제 — 고정된 세션은 항상 목록 최상단에 표시됩니다" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "固定 / 取消固定 — 固定的会话会保留在列表顶部" - } - } - } - }, - "Plan" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "계획 모드" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划" - } - } - } - }, - "Platform: %@ • %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Platform: %1$@ • %2$@" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "平台:%1$@ • %2$@" - } - } - } - }, - "Preference" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "偏好" - } - } - } - }, - "Preset" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "预设" - } - } - } - }, - "Preset Name" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "预设名称" - } - } - } - }, - "Press Command-K or use the toolbar search button to find past work across projects." : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "按 Command-K 或使用工具栏搜索按钮,在各项目中查找过去的工作。" - } - } - } - }, - "Preview" : { + "focus.mode.desc" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Preview" + "value" : "Hide streaming bubbles and show only completed responses in history." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "미리보기" + "value" : "스트리밍 중 메시지 버블을 숨기고, 완료된 응답만 히스토리에 표시합니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "预览" + "value" : "隐藏流式输出气泡,只在历史记录中显示已完成的回复。" } } } }, - "Previous conversation has been compacted" : { - "extractionState" : "stale", + "Font Size" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Previous conversation has been compacted" + "value" : "Font Size" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이전 대화가 압축되었습니다" + "value" : "폰트 크기" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "之前的对话已压缩" + "value" : "字体大小" } } } }, - "Private repository" : { - "extractionState" : "stale", + "font.size.hint" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Private repository" + "value" : "Adjust interface and message font sizes independently." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "비공개 저장소" + "value" : "인터페이스와 메시지 폰트 크기를 각각 조절합니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "私有仓库" + "value" : "分别调整界面和消息字体大小。" } } } }, - "Project" : { + "Force off" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目" + "value" : "强制关闭" } } } }, - "Project / Workspace" : { + "Force on" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目 / 工作区" + "value" : "强制开启" } } } }, - "Project Management" : { - "extractionState" : "stale", + "from %@" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Project Management" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트 관리" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目管理" + "value" : "来自 %@" } } } }, - "Project name" : { + "General" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Project name" + "value" : "General" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트 이름" + "value" : "일반" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目名称" + "value" : "通用" } } } }, - "Project Name" : { + "Generate" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目名称" + "value" : "生成" } } } }, - "Project path — folder path of the currently selected project (home directory abbreviated as ~)" : { - "extractionState" : "stale", + "Generate a commit message from the staged diff" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Project path — folder path of the currently selected project (home directory abbreviated as ~)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트 경로 — 현재 선택된 프로젝트의 폴더 경로 (홈 디렉토리는 ~로 축약)" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目路径 — 当前所选项目的文件夹路径(主目录缩写为 ~)" + "value" : "根据已暂存差异生成提交消息" } } } }, - "Project tab — open in dedicated window" : { - "extractionState" : "stale", + "Get Started" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Project tab — open in dedicated window" + "value" : "Get Started" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트 탭 — 전용 창에서 열기" + "value" : "시작하기" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目标签页 — 在专用窗口中打开" + "value" : "开始使用" } } } }, - "Project Tabs" : { - "extractionState" : "stale", + "Git Repositories" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Project Tabs" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트 탭" + "value" : "Git 仓库" } - }, + } + } + }, + "Git URL" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目标签页" + "value" : "Git URL" } } } }, - "Project tabs appear at the top of the chat area. Click a tab to switch projects. You can switch even while Claude is streaming — the active stream continues in the background." : { - "extractionState" : "stale", + "GitHub" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Project tabs appear at the top of the chat area. Click a tab to switch projects. You can switch even while Claude is streaming — the active stream continues in the background." + "value" : "GitHub" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "채팅 영역 상단에 프로젝트 탭이 표시됩니다. 탭을 클릭하여 전환하세요. Claude가 스트리밍 중에도 전환 가능하며, 진행 중인 스트림은 백그라운드에서 계속 실행됩니다." + "value" : "GitHub" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目标签页显示在聊天区域顶部。点击标签页即可切换项目。即使 Claude 正在流式输出,也可以切换;当前流会在后台继续。" + "value" : "GitHub" } } } }, - "Project-specific override is set" : { + "GitHub Repository" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已设置项目级覆盖" + "value" : "GitHub 仓库" } } } }, - "Project: Off" : { + "Global" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目:关闭" + "value" : "全局" } } } }, - "Project: On" : { + "Global default" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目:开启" + "value" : "全局默认" } } } }, - "Projects" : { + "Global default plus per-project override" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Projects" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "프로젝트" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "项目" + "value" : "全局默认值加项目级覆盖" } } } }, - "Provider" : { + "Headers" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "提供方" + "value" : "标头" } } } }, - "Public repository" : { - "extractionState" : "stale", + "Hide details" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Public repository" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "공개 저장소" + "value" : "隐藏详情" } - }, + } + } + }, + "Hide Hidden Files" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "公开仓库" + "value" : "隐藏隐藏文件" } } } }, - "Push" : { + "Hide more" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "推送" + "value" : "隐藏更多" } } } }, - "Quick-access buttons shown at the top of the chat area. Run frequently used messages or shell commands with a single click." : { - "extractionState" : "stale", + "History" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Quick-access buttons shown at the top of the chat area. Run frequently used messages or shell commands with a single click." + "value" : "History" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "채팅 영역 상단에 표시되는 빠른 접근 버튼입니다. 자주 사용하는 메시지나 셸 커맨드를 한 번의 클릭으로 실행할 수 있습니다." + "value" : "기록" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示在聊天区域顶部的快速访问按钮。单击即可运行常用消息或 shell 命令。" + "value" : "历史" } } } }, - "Quit" : { + "https://example.com/mcp" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "退出" + "value" : "https://example.com/mcp" } } } }, - "Re-run %@" : { + "https://github.com/owner/repo" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重新运行 %@" + "value" : "https://github.com/owner/repo" + } + } + } + }, + "https://github.com/owner/repo.git or git@github.com:owner/repo.git" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "https://github.com/owner/repo.git or git@github.com:owner/repo.git" } } } }, - "Read failed: %@" : { - "extractionState" : "stale", + "Images" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Read failed: %@" + "value" : "Images" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "읽기 실패: %@" + "value" : "이미지" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "读取失败:%@" + "value" : "图片" } } } }, - "Read-only — analyzes and plans without making edits" : { - "extractionState" : "stale", + "In progress" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Read-only — analyzes and plans without making edits" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "파일 읽기만 허용, 실제 편집 없이 계획만 제시" + "value" : "进行中" } - }, + } + } + }, + "Inactive chats are moved to the archive automatically. Pinned chats are never auto-archived." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "只读 — 仅分析和规划,不进行编辑" + "value" : "不活跃聊天会自动移入归档。固定的聊天永远不会自动归档。" } } } }, - "Reasoning effort applied to new sessions" : { - "extractionState" : "stale", + "Include relevant memories in agent context" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reasoning effort applied to new sessions" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "새 세션에 적용될 추론 작업량" + "value" : "在智能体上下文中包含相关记忆" } - }, + } + } + }, + "Inherit global default" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "应用于新会话的推理强度" + "value" : "继承全局默认值" } } } }, - "Recall previous message" : { - "extractionState" : "stale", + "Initialize Git" : { + + }, + "Initializing…" : { + + }, + "Install" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Recall previous message" + "value" : "Install" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이전 메시지 불러오기" + "value" : "설치" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "调出上一条消息" + "value" : "安装" + } + } + } + }, + "Install ACP agents" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "安装 ACP 智能体" } } } }, - "Recalling Previous Messages" : { - "extractionState" : "stale", + "Installed" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Recalling Previous Messages" + "value" : "Installed" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이전 메시지 불러오기" + "value" : "설치됨" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "调出之前的消息" - } - } - } - }, - "Recent Briefings" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "最近简报" + "value" : "已安装" } } } }, - "Reconnecting in %llds" : { + "Installed skills are managed by RxCode, sourced from OpenAI Agent Skills and compatible catalogs, and enabled for Claude Code, Codex, and ACP agents where supported." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%lld 秒后重新连接" + "value" : "已安装技能由 RxCode 管理,来源于 OpenAI Agent Skills 和兼容目录,并会在支持的 Claude Code、Codex 和 ACP 智能体中启用。" } } } }, - "Refresh" : { + "Installing..." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Refresh" + "value" : "Installing..." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "새로고침" + "value" : "설치 중..." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "刷新" + "value" : "正在安装..." } } } }, - "Refresh & Test All" : { + "Interface" : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Interface" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "인터페이스" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "刷新并测试全部" + "value" : "界面" } } } }, - "Refresh installation status" : { + "Keep summaries on the thread model, or route titles and briefings through an OpenAI-compatible endpoint." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "刷新安装状态" + "value" : "可使用对话模型生成摘要,或通过 OpenAI 兼容端点处理标题和简报。" } } } }, - "Refresh registry" : { + "KEY" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "刷新注册表" + "value" : "KEY" } } } }, - "Refresh usage" : { + "Kind" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "刷新用量" + "value" : "类型" } } } }, - "Regenerate" : { + "Live channel only" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重新生成" + "value" : "仅实时通道" } } } }, - "Registry" : { + "Load from .env file" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "注册表" + "value" : "从 .env 文件加载" } } } }, - "Reindex all threads" : { + "Loading catalog..." : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Loading catalog..." + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "카탈로그 불러오는 중..." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重新索引所有对话" + "value" : "正在加载目录..." } } } }, - "Reindex Now" : { + "Loading destinations…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "立即重新索引" + "value" : "正在加载目标…" } } } }, - "Reject" : { + "Loading registry…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "拒绝" + "value" : "正在加载注册表…" } } } }, - "Reject the action" : { - "extractionState" : "stale", + "Loading repos..." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Reject the action" + "value" : "Loading repos..." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "작업 거부" + "value" : "저장소 불러오는 중..." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "拒绝操作" + "value" : "正在加载仓库..." } } } }, - "Relay server" : { + "Loading..." : { "localizations" : { - "zh-Hans" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Loading..." + } + }, + "ko" : { "stringUnit" : { "state" : "translated", - "value" : "中继服务器" + "value" : "불러오는 중..." } - } - } - }, - "Relay servers" : { - "localizations" : { + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "中继服务器" + "value" : "正在加载..." } } } }, - "Relay:" : { + "Local" : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Local" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "로컬" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "中继:" + "value" : "本地" } } } }, - "Remote" : { + "Local on-device search · archived threads included" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "远程" + "value" : "本地设备端搜索 · 包含已归档对话" } } } }, - "Remote (origin)" : { - "extractionState" : "stale", + "Long text (200+ characters)" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Remote (origin)" + "value" : "Long text (200+ characters)" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "원격 (origin)" + "value" : "긴 텍스트 (200자 이상)" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "远程 (origin)" + "value" : "长文本(200 字符以上)" } } } }, - "Remove" : { + "main" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Remove" + "state" : "translated", + "value" : "main" } - }, - "ko" : { + } + } + }, + "Make" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "제거" + "value" : "Make" } - }, + } + } + }, + "Makefile" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "移除" + "value" : "Makefile" } } } }, - "Remove ACP client?" : { + "Makefile (optional)" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "移除 ACP 客户端?" + "value" : "Makefile(可选)" } } } }, - "Remove MCP server?" : { + "Malformed question payload" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "移除 MCP 服务器?" + "value" : "问题载荷格式错误" } } } }, - "Remove Variable" : { + "Manage" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "移除变量" + "value" : "管理" } } } }, - "Remove…" : { + "Manage agents that speak the Agent Client Protocol. Detected from agentclientprotocol.com." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "移除…" + "value" : "管理使用 Agent Client Protocol 的智能体。从 agentclientprotocol.com 检测。" } } } }, - "Rename" : { + "Manage GitHub Repos" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Rename" + "value" : "Manage GitHub Repos" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이름 변경" + "value" : "GitHub 저장소 관리" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名" + "value" : "管理 GitHub 仓库" } } } }, - "Rename — change the session title" : { - "extractionState" : "stale", + "Manage MCP servers once in RxCode, then enable or disable them globally or per project." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Rename — change the session title" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "이름 변경 — 세션 제목을 수정합니다" + "value" : "在 RxCode 中统一管理 MCP 服务器,然后全局或按项目启用/禁用。" } - }, + } + } + }, + "Manual key/value pairs" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名 — 更改会话标题" + "value" : "手动键/值对" } } } }, - "Rename device" : { + "Matched on title" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名设备" + "value" : "按标题匹配" } } } }, - "Rename Device" : { + "MCP" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名设备" + "value" : "MCP" } } } }, - "Rename Project" : { + "MCP error" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Rename Project" + "state" : "translated", + "value" : "MCP 错误" } - }, - "ko" : { + } + } + }, + "MCP server disconnected" : { + "comment" : "Notification title when an MCP server transitions from connected to failed.", + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트 이름 변경" + "value" : "MCP 服务器已断开连接" } - }, + } + } + }, + "MCP Servers" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名项目" + "value" : "MCP 服务器" } } } }, - "Rename Session" : { + "Memo" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Rename Session" + "value" : "Memo" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "세션 이름 변경" + "value" : "메모" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名会话" + "value" : "备忘" } } } }, - "Rename…" : { + "Memory" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重命名…" + "value" : "记忆" } } } }, - "Reset" : { + "Memory History" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reset" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "초기화" + "value" : "记忆历史" } - }, + } + } + }, + "Menu Bar" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重置" + "value" : "菜单栏" } } } }, - "Reset Buttons" : { - "extractionState" : "stale", + "Message" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Reset Buttons" + "value" : "Message" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "리셋 버튼" + "value" : "메시지" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重置按钮" + "value" : "消息" } } } }, - "Reset Terminal" : { + "Messages" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Reset Terminal" + "value" : "Messages" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "터미널 리셋" + "value" : "메시지" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重置终端" + "value" : "消息" } } } }, - "Reset to project root" : { + "Mobile" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重置为项目根目录" + "value" : "移动端" } } } }, - "Resets %@" : { + "Mobile companion" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重置 %@" + "value" : "移动伴侣应用" } } } }, - "Response complete" : { - "comment" : "Notification body when Claude finishes a response", + "Model" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "模型" + } + } + } + }, + "Model Picker" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Response complete" + "value" : "Model Picker" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "응답 완료" + "value" : "모델" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "回复完成" + "value" : "模型选择器" } } } }, - "Response in progress" : { - - }, - "Response in progress in the background" : { - "extractionState" : "stale", + "Model: %@ · %@" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Response in progress in the background" + "value" : "Model: %1$@ · %2$@" } }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "백그라운드에서 응답 진행 중" + "value" : "模型:%1$@ · %2$@" } - }, + } + } + }, + "Models" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "回复正在后台进行" + "value" : "模型" } } } }, - "Response in progress. Todos %lld/%lld" : { + "More" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Response in progress. Todos %1$lld/%2$lld" + "state" : "translated", + "value" : "更多" } } } }, - "Retry" : { + "My Relay Server" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Retry" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "재시도" + "value" : "我的中继服务器" } - }, + } + } + }, + "my-project" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "重试" + "value" : "my-project" } } } }, - "Reveal in Finder" : { + "my-server" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 Finder 中显示" + "value" : "my-server" } } } }, - "Review the CLI setup check" : { + "Name" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "查看 CLI 设置检查" + "value" : "名称" } } } }, - "Right-click a session in the History tab for context menu options." : { - "extractionState" : "stale", + "New Chat" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Right-click a session in the History tab for context menu options." + "value" : "New Chat" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "기록 탭에서 세션을 우클릭하면 컨텍스트 메뉴가 표시됩니다." + "value" : "새 채팅" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在“历史”标签页中右键点击会话可查看上下文菜单选项。" + "value" : "新建聊天" } } } }, - "Run %@" : { + "New Chat in %@" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "运行 %@" + "value" : "在 %@ 中新建聊天" } } } }, - "Run/Debug Configurations" : { + "New Terminal" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "运行/调试配置" + "value" : "新建终端" } } } }, - "Runs `make [-f ] [arguments]`. Leave Makefile empty to use the default lookup (Makefile / makefile / GNUmakefile)." : { + "New Terminal (⌘T)" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "运行 `make [-f ] [arguments]`。留空 Makefile 会使用默认查找(Makefile / makefile / GNUmakefile)。" + "value" : "新建终端(⌘T)" } } } }, - "Runs on-device with Apple Intelligence. Private, free, and offline." : { + "Next" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "通过 Apple Intelligence 在设备端运行。私密、免费且离线。" + "value" : "下一步" } } } }, - "RxCode" : { + "No active runs" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode" + "value" : "没有正在运行的任务" } } } }, - "RxCode ships with six accent color themes. Preview each one directly from the theme picker — the whole app recolors live as you choose." : { - "extractionState" : "stale", + "No agents match “%@”." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "RxCode ships with six accent color themes. Preview each one directly from the theme picker — the whole app recolors live as you choose." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode는 6가지 강조 색상 테마를 제공합니다. 테마 선택기에서 바로 각 테마를 미리볼 수 있으며, 선택과 동시에 앱 전체 색상이 즉시 바뀝니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode 内置六种强调色主题。可直接在主题选择器中预览;选择时整个应用会实时换色。" + "value" : "没有匹配“%@”的智能体。" } } } }, - "RxCode.xcodeproj" : { + "No archived chats" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode.xcodeproj" + "value" : "没有已归档聊天" } } } }, - "rxcode/feature-name" : { + "No changes" : { "localizations" : { - "zh-Hans" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No changes" + } + }, + "ko" : { "stringUnit" : { "state" : "translated", - "value" : "rxcode/feature-name" + "value" : "변경사항 없음" } - } - } - }, - "Save" : { - "localizations" : { + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "保存" + "value" : "没有变更" } } } }, - "Save failed: %@" : { - "extractionState" : "stale", + "No chat history" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Save failed: %@" + "value" : "No chat history" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "저장 실패: %@" + "value" : "채팅 기록 없음" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "保存失败:%@" + "value" : "没有聊天历史" } } } }, - "Save file changes" : { - "extractionState" : "stale", + "No chats yet" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Save file changes" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "파일 변경사항 저장" + "value" : "还没有聊天" } - }, + } + } + }, + "No clients installed. Add one from the Registry tab." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "保存文件更改" + "value" : "未安装客户端。请从“注册表”标签页添加一个。" } } } }, - "Saved memories are stored locally in SwiftData and embedded on-device." : { + "No custom Git sources" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "保存的记忆会存储在本地 SwiftData 中,并在设备端嵌入。" + "value" : "没有自定义 Git 来源" } } } }, - "Saved memory history is available from Manage." : { + "No custom Git sources added." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "可从“管理”查看已保存的记忆历史。" + "value" : "尚未添加自定义 Git 来源。" } } } }, - "Saving and probing…" : { + "No custom repositories" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "正在保存并探测…" + "value" : "没有自定义仓库" } } } }, - "Scan with the RxCode app on your iPhone or iPad." : { + "No destinations found" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用 iPhone 或 iPad 上的 RxCode 应用扫描。" + "value" : "未找到目标" } } } }, - "Scheme" : { + "No editors detected" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Scheme" + "value" : "未检测到编辑器" } } } }, - "Scope" : { + "No environment variables defined" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "范围" + "value" : "未定义环境变量" } } } }, - "Screenshots can be pasted directly — they are automatically attached as images." : { - "extractionState" : "stale", + "No local branches" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Screenshots can be pasted directly — they are automatically attached as images." + "value" : "No local branches" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "스크린샷을 바로 붙여넣을 수 있으며 자동으로 이미지로 첨부됩니다." + "value" : "로컬 브랜치 없음" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "截图可以直接粘贴,并会自动作为图像附加。" + "value" : "没有本地分支" } } } }, - "Search agents" : { + "No matching memories" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索智能体" + "value" : "没有匹配的记忆" } } } }, - "Search every thread" : { + "No memories" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索每个对话" + "value" : "没有记忆" } } } }, - "Search filename..." : { + "No paired devices yet." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Search filename..." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 이름 검색..." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索文件名..." + "value" : "尚未配对设备。" } } } }, - "Search Files (⌘F)" : { + "No profiles for this project" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Search Files (⌘F)" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "파일 검색 (⌘F)" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索文件 (⌘F)" + "value" : "此项目没有配置" } } } }, - "Search for a repository by name, then click Add. RxCode clones it automatically and opens it as a new project." : { - "extractionState" : "stale", + "No profiles yet" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Search for a repository by name, then click Add. RxCode clones it automatically and opens it as a new project." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "이름으로 저장소를 검색한 후 추가 버튼을 클릭하세요. RxCode가 자동으로 클론하고 새 프로젝트로 엽니다." + "value" : "还没有配置" } - }, + } + } + }, + "No project" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "按名称搜索仓库,然后点击“添加”。RxCode 会自动克隆该仓库并将其作为新项目打开。" + "value" : "没有项目" } } } }, - "Search Index" : { + "No projects yet" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索索引" + "value" : "还没有项目" } } } }, - "Search memory" : { + "No relay servers" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索记忆" + "value" : "没有中继服务器" } } } }, - "Search repos..." : { + "No remote branches" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Search repos..." + "value" : "No remote branches" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "저장소 검색..." + "value" : "원격 브랜치 없음" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "搜索仓库..." + "value" : "没有远程分支" } } } }, - "Search skills..." : { + "No repos found" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Search skills..." + "value" : "No repos found" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "스킬 검색..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "搜索技能..." - } - } - } - }, - "Search Threads (⌘K)" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "搜索对话(⌘K)" + "value" : "저장소를 찾을 수 없습니다" } - } - } - }, - "Search threads by topic, keyword, or feel…" : { - "localizations" : { + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "按主题、关键词或感觉搜索对话…" + "value" : "未找到仓库" } } } }, - "Select a Project" : { + "No results for '%@'" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Select a Project" + "value" : "No results for '%@'" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "프로젝트를 선택하세요" + "value" : "'%@'에 대한 검색 결과 없음" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择项目" + "value" : "没有“%@”的结果" } } } }, - "Select a project from the sidebar or add a new one." : { + "No results found" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Select a project from the sidebar or add a new one." + "value" : "No results found" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "사이드바에서 프로젝트를 선택하거나 새로 추가하세요." + "value" : "검색 결과 없음" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "从侧边栏选择一个项目,或添加新项目。" + "value" : "未找到结果" } } } }, - "Select a target…" : { + "No servers" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择目标…" + "value" : "没有服务器" } } } }, - "Select All in Section" : { + "No summary yet" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择本节全部" + "value" : "还没有摘要" } } } }, - "Select all that apply" : { + "No tasks" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择所有适用项" + "value" : "没有任务" } } } }, - "Select Effort Level" : { + "No tools advertised." : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "未声明任何工具。" + } + } + } + }, + "None" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无" + } + } + } + }, + "Not a Git repository" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Select Effort Level" + "value" : "Not a Git repository" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "Effort 수준 선택" + "value" : "Git 저장소가 아닙니다" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择推理强度" + "value" : "不是 Git 仓库" + } + } + } + }, + "Not found" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "未找到" } } } }, - "Select item" : { - "extractionState" : "stale", + "Notifications" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Select item" + "value" : "Notifications" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "항목 선택" + "value" : "알림" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择项目" + "value" : "通知" } } } }, - "Select Model" : { + "Notify when response completes" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Select Model" + "value" : "Notify when response completes" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "모델 선택" + "value" : "응답 완료 시 알림" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择模型" + "value" : "回复完成时通知" } } } }, - "Select or add a profile to edit" : { + "npx" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择或添加要编辑的配置" + "value" : "npx" + } + } + } + }, + "Offline" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "离线" } } } }, - "Select popup item or navigate message history" : { - "extractionState" : "stale", + "OK" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Select popup item or navigate message history" + "value" : "OK" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "팝업 항목 선택 또는 메시지 기록 탐색" + "value" : "확인" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择弹出项或浏览消息历史" + "value" : "确定" } } } }, - "Select relay" : { + "Online" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择中继" + "value" : "在线" } } } }, - "Select Run Destination" : { + "Open in External Editor" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择运行目标" + "value" : "在外部编辑器中打开" } } } }, - "Select Run Profile" : { + "Open in GitHub" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "选择运行配置" + "value" : "在 GitHub 中打开" } } } }, - "Send message" : { - "extractionState" : "stale", + "Open in New Window" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Send message" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "메시지 전송" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "发送消息" + "value" : "在新窗口中打开" } } } }, - "Send message (alternative)" : { - "extractionState" : "stale", + "Open Project" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Send message (alternative)" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "메시지 전송 (대체)" + "value" : "打开项目" } - }, + } + } + }, + "Open project branch briefing" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "发送消息(备用)" + "value" : "打开项目分支简报" } } } }, - "Send test notification" : { + "Open RxCode" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "发送测试通知" + "value" : "打开 RxCode" } } } }, - "Sending Messages" : { - "extractionState" : "stale", + "Open Source" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Sending Messages" + "value" : "Open Source" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "메시지 전송" + "value" : "오픈 소스" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "发送消息" + "value" : "开源" } } } }, - "Sends a system notification while RxCode is in the background." : { + "Open Terminal (⌥-click for window)" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Sends a system notification while RxCode is in the background." + "state" : "translated", + "value" : "打开终端(⌥-点击打开窗口)" } - }, - "ko" : { + } + } + }, + "Open the branch briefing" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode가 백그라운드에 있을 때 시스템 알림을 보냅니다." + "value" : "打开分支简报" } - }, + } + } + }, + "OpenAI-Compatible Endpoint" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "当 RxCode 在后台时发送系统通知。" + "value" : "OpenAI 兼容端点" } } } }, - "Servers" : { + "Opus 4.6 only" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "服务器" + "value" : "Opus 4.6 only" } } } }, - "Session name" : { + "Other" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Session name" + "state" : "translated", + "value" : "其他" } - }, - "ko" : { + } + } + }, + "Override" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "세션 이름" + "value" : "覆盖" } - }, + } + } + }, + "Pair a new device" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "会话名称" + "value" : "配对新设备" } } } }, - "Set the summarization model" : { + "Pair an iPhone or iPad to review threads, answer approvals, and send messages to your desktop agent." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "设置摘要模型" + "value" : "配对 iPhone 或 iPad,以查看对话、响应批准请求,并向桌面智能体发送消息。" } } } }, - "Settings" : { + "Pair an iPhone or iPad to view threads, get notifications, and send messages to your desktop agent." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "设置" + "value" : "配对 iPhone 或 iPad,以查看对话、接收通知,并向桌面智能体发送消息。" } } } }, - "Settings & Themes" : { - "extractionState" : "stale", + "Pair new device" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Settings & Themes" + "state" : "translated", + "value" : "配对新设备" } - }, - "ko" : { + } + } + }, + "Paired devices" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "설정 및 테마" + "value" : "已配对设备" } - }, + } + } + }, + "Permanently delete archived chats after the retention window. Pinned chats are never auto-deleted. This cannot be undone." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "设置和主题" + "value" : "在保留期后永久删除归档聊天。置顶聊天不会被自动删除。此操作无法撤销。" } } } }, - "Share session history with the terminal CLI in ~/.claude/projects/. Turn off to keep RxCode sessions separate. You can change this later in Settings." : { - "extractionState" : "stale", + "Permission Mode" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Share session history with the terminal CLI in ~/.claude/projects/. Turn off to keep RxCode sessions separate. You can change this later in Settings." + "value" : "Permission Mode" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "~/.claude/projects/의 터미널 CLI와 세션 기록을 공유합니다. 끄면 RxCode 세션을 분리해서 사용합니다. 이후 설정에서 변경할 수 있습니다." + "value" : "권한 모드" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "与 ~/.claude/projects/ 中的终端 CLI 共享会话历史。关闭后,RxCode 会话将单独保存。你之后可在设置中更改。" + "value" : "权限模式" } } } }, - "Shortcut Buttons" : { - "extractionState" : "stale", + "Permission mode: %@" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Shortcut Buttons" + "value" : "Permission mode: %@" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "단축 버튼" + "value" : "권한 모드: %@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷按钮" + "value" : "权限模式:%@" } } } }, - "Shortcuts" : { + "Permission needed%@" : { + "comment" : "Notification title when Claude queues a tool approval. %@ is replaced with \" — \" or empty string.", "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Shortcuts" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축키" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷方式" + "value" : "需要权限%@" } } } }, - "Show a preview chip when a file path is detected" : { - "extractionState" : "stale", + "Permission Request" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Show a preview chip when a file path is detected" + "value" : "Permission Request" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "파일 경로 감지 시 미리보기 칩을 표시합니다." + "value" : "권한 요청" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "检测到文件路径时显示预览标签" + "value" : "权限请求" } } } }, - "Show a preview chip when a URL is detected" : { - "extractionState" : "stale", + "Pick a profile in the toolbar and press Run." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Show a preview chip when a URL is detected" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "URL 감지 시 미리보기 칩을 표시합니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "检测到 URL 时显示预览标签" + "value" : "在工具栏中选择配置并按“运行”。" } } } }, - "Show a preview chip when image data is detected" : { - "extractionState" : "stale", + "Pin" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Show a preview chip when image data is detected" + "value" : "Pin" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "이미지 데이터 감지 시 미리보기 칩을 표시합니다." + "value" : "고정" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "检测到图像数据时显示预览标签" + "value" : "固定" } } } }, - "Show a system notification when a response completes while RxCode is in the background" : { - "extractionState" : "stale", + "Platform: %@ • %@" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Show a system notification when a response completes while RxCode is in the background" + "value" : "Platform: %1$@ • %2$@" } }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode가 백그라운드에 있을 때 응답이 완료되면 시스템 알림 표시" + "value" : "平台:%1$@ • %2$@" } - }, + } + } + }, + "Preference" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode 在后台时,响应完成后显示系统通知" + "value" : "偏好" } } } }, - "Show active chats" : { + "Preset" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示活跃聊天" + "value" : "预设" } } } }, - "Show all chats" : { + "Preset Name" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示所有聊天" + "value" : "预设名称" } } } }, - "Show all projects" : { + "Press Command-K or use the toolbar search button to find past work across projects." : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "按 Command-K 或使用工具栏搜索按钮,在各项目中查找过去的工作。" + } + } + } + }, + "Preview" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Show all projects" + "value" : "Preview" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "모든 프로젝트 표시" + "value" : "미리보기" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示所有项目" + "value" : "预览" } } } }, - "Show all threads in this project" : { + "Project" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示此项目中的所有对话" + "value" : "项目" } } } }, - "Show archived chats" : { + "Project / Workspace" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示已归档聊天" + "value" : "项目 / 工作区" } } } }, - "Show current project only" : { + "Project name" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Show current project only" + "value" : "Project name" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "현재 프로젝트만 표시" + "value" : "프로젝트 이름" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "仅显示当前项目" + "value" : "项目名称" } } } }, - "Show Hidden Files" : { + "Project Name" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示隐藏文件" + "value" : "项目名称" } } } }, - "Show in Finder" : { + "Project-specific override is set" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Show in Finder" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Finder에서 보기" + "value" : "已设置项目级覆盖" } - }, + } + } + }, + "Project: Off" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 Finder 中显示" + "value" : "项目:关闭" } } } }, - "Show menu bar icon" : { + "Project: On" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示菜单栏图标" + "value" : "项目:开启" } } } }, - "Show more" : { + "Projects" : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Projects" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "프로젝트" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示更多" + "value" : "项目" } } } }, - "Show Onboarding" : { + "Provider" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示入门引导" + "value" : "提供方" } } } }, - "Show only the first five threads" : { + "Push" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "仅显示前五个对话" + "value" : "推送" } } } }, - "Show thread summary" : { + "Quit" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示对话摘要" + "value" : "退出" } } } }, - "Showing effective MCP state for this project" : { + "Re-run %@" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示此项目的有效 MCP 状态" + "value" : "重新运行 %@" } } } }, - "Showing global MCP defaults" : { + "Recent Briefings" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示全局 MCP 默认值" + "value" : "最近简报" } } } }, - "Shows in-progress chat counts and Claude Code usage limits in the macOS menu bar." : { + "Reconnecting in %llds" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 macOS 菜单栏中显示进行中的聊天数量和 Claude Code 用量限制。" + "value" : "%lld 秒后重新连接" } } } }, - "Sidebar — Files tab (expands sidebar if hidden)" : { - "extractionState" : "stale", + "Refresh" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Sidebar — Files tab (expands sidebar if hidden)" + "value" : "Refresh" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "사이드바 — 파일 탭 (숨겨진 경우 사이드바 펼침)" + "value" : "새로고침" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "边栏 — 文件标签页(如果边栏隐藏则展开)" + "value" : "刷新" } } } }, - "Sidebar — Files tab + search" : { - "extractionState" : "stale", + "Refresh & Test All" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Sidebar — Files tab + search" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사이드바 — 파일 탭 + 검색" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "边栏 — 文件标签页 + 搜索" + "value" : "刷新并测试全部" } } } }, - "Sidebar — History tab (expands sidebar if hidden)" : { - "extractionState" : "stale", + "Refresh installation status" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Sidebar — History tab (expands sidebar if hidden)" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "사이드바 — 기록 탭 (숨겨진 경우 사이드바 펼침)" + "value" : "刷新安装状态" } - }, + } + } + }, + "Refresh registry" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "边栏 — 历史标签页(如果边栏隐藏则展开)" + "value" : "刷新注册表" } } } }, - "Sidebar Tabs" : { - "extractionState" : "stale", + "Refresh usage" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Sidebar Tabs" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "사이드바 탭" + "value" : "刷新用量" } - }, + } + } + }, + "Regenerate" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "边栏标签页" + "value" : "重新生成" } } } }, - "Sign in with GitHub" : { + "Registry" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Sign in with GitHub" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "GitHub로 로그인" + "value" : "注册表" } - }, + } + } + }, + "Reindex all threads" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用 GitHub 登录" + "value" : "重新索引所有对话" } } } }, - "sk-..." : { + "Reindex Now" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "sk-..." + "value" : "立即重新索引" } } } }, - "Skill Marketplace" : { + "Reject" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skill Marketplace" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "스킬 마켓플레이스" + "value" : "拒绝" } - }, + } + } + }, + "Relay server" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "技能市场" + "value" : "中继服务器" } } } }, - "Skip All Questions" : { + "Relay servers" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过所有问题" + "value" : "中继服务器" } } } }, - "Skip mode — all permissions auto-approved" : { - "extractionState" : "stale", + "Relay:" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skip mode — all permissions auto-approved" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "건너뛰기 모드 — 모든 권한이 자동 승인됩니다" + "value" : "中继:" } - }, + } + } + }, + "Remote" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过模式 — 自动批准所有权限" + "value" : "远程" } } } }, - "Skip Permissions" : { - "extractionState" : "stale", + "Remove" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Skip Permissions" + "value" : "Remove" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "권한 건너뛰기" + "value" : "제거" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过权限" + "value" : "移除" } } } }, - "Skip Permissions Mode" : { - "extractionState" : "stale", + "Remove ACP client?" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skip Permissions Mode" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "권한 건너뛰기 모드" + "value" : "移除 ACP 客户端?" } - }, + } + } + }, + "Remove MCP server?" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过权限模式" + "value" : "移除 MCP 服务器?" } } } }, - "Skip Permissions: OFF" : { - "extractionState" : "stale", + "Remove Variable" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skip Permissions: OFF" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "권한 건너뛰기: 꺼짐" + "value" : "移除变量" } - }, + } + } + }, + "Remove…" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过权限:关" + "value" : "移除…" } } } }, - "Skip Permissions: ON" : { - "extractionState" : "stale", + "Rename" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Skip Permissions: ON" + "value" : "Rename" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "권한 건너뛰기: 켜짐" + "value" : "이름 변경" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过权限:开" + "value" : "重命名" } } } }, - "Skips all permission checks — use only in isolated environments" : { - "extractionState" : "stale", + "Rename device" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Skips all permission checks — use only in isolated environments" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "모든 권한 검사 생략 — 격리된 환경에서만 사용 권장" + "value" : "重命名设备" } - }, + } + } + }, + "Rename Device" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过所有权限检查 — 仅在隔离环境中使用" + "value" : "重命名设备" } } } }, - "Skips all permission checks — writes to .git/.vscode/.claude directories still require approval" : { - "extractionState" : "stale", + "Rename Project" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Skips all permission checks — writes to .git/.vscode/.claude directories still require approval" + "value" : "Rename Project" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "모든 권한 검사 생략 — .git/.vscode/.claude 디렉토리 쓰기는 여전히 승인 필요" + "value" : "프로젝트 이름 변경" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "跳过所有权限检查 — 写入 .git/.vscode/.claude 目录仍需批准" + "value" : "重命名项目" } } } }, - "Slash Command Popup" : { - "extractionState" : "stale", + "Rename Session" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Slash Command Popup" + "value" : "Rename Session" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "슬래시 커맨드 팝업" + "value" : "세션 이름 변경" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "斜杠命令弹出框" + "value" : "重命名会话" } } } }, - "Slash Commands" : { + "Rename…" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Slash Commands" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "斜杠命令" + "value" : "重命名…" } } } }, - "Slash Commands & Shortcuts Tabs" : { - "extractionState" : "stale", + "Reset" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Slash Commands & Shortcuts Tabs" + "value" : "Reset" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "슬래시 커맨드 및 단축키 탭" + "value" : "초기화" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "斜杠命令和快捷按钮标签页" + "value" : "重置" } } } }, - "Soft purple" : { - "extractionState" : "stale", + "Reset Terminal" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Soft purple" + "value" : "Reset Terminal" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "부드러운 퍼플" + "value" : "터미널 리셋" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "柔紫色" + "value" : "重置终端" } } } }, - "Some commands (such as /config, /permissions, /model) open in a full interactive terminal popup sheet, where you can use the interactive CLI interface. The popup closes automatically when the command finishes." : { - "extractionState" : "stale", + "Reset to project root" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Some commands (such as /config, /permissions, /model) open in a full interactive terminal popup sheet, where you can use the interactive CLI interface. The popup closes automatically when the command finishes." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "/config, /permissions, /model 등 일부 커맨드는 별도의 인터랙티브 터미널 팝업 시트에서 실행됩니다. 커맨드가 완료되면 자동으로 닫힙니다." + "value" : "重置为项目根目录" } - }, + } + } + }, + "Resets %@" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "某些命令(如 /config、/permissions、/model)会在完整的交互式终端弹窗表单中打开,你可以在其中使用交互式 CLI 界面。命令完成后弹窗会自动关闭。" + "value" : "重置 %@" } } } }, - "Some slash commands (such as /config, /permissions, /model) open in a separate interactive terminal sheet. The popup runs the command automatically and closes when it exits." : { - "extractionState" : "stale", + "Response complete" : { + "comment" : "Notification body when Claude finishes a response", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Some slash commands (such as /config, /permissions, /model) open in a separate interactive terminal sheet. The popup runs the command automatically and closes when it exits." + "value" : "Response complete" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "일부 슬래시 커맨드(/config, /permissions, /model 등)는 별도의 대화형 터미널 시트에서 열립니다. 팝업이 커맨드를 자동으로 실행하고 종료 시 닫힙니다." + "value" : "응답 완료" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "某些斜杠命令(如 /config、/permissions、/model)会在单独的交互式终端表单中打开。弹窗会自动运行命令,并在退出时关闭。" + "value" : "回复完成" } } } }, - "Source" : { + "Response in progress" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "来源" + "value" : "响应进行中" } } } }, - "Start new chat" : { - "extractionState" : "stale", + "Response in progress. Todos %lld/%lld" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Response in progress. Todos %1$lld/%2$lld" + } + } + } + }, + "Retry" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Start new chat" + "value" : "Retry" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "새 채팅 시작" + "value" : "재시도" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "开始新聊天" + "value" : "重试" } } } }, - "Start New Chat" : { + "Reveal in Finder" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "开始新聊天" + "value" : "在 Finder 中显示" } } } }, - "Status Line" : { - "extractionState" : "stale", + "Review the CLI setup check" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Status Line" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상태 표시줄" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "状态行" + "value" : "查看 CLI 设置检查" } } } }, - "Stop '%@'" : { + "Run %@" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "停止“%@”" + "value" : "运行 %@" } } } }, - "Stop %@" : { + "Run git init in this project" : { + + }, + "Run/Debug Configurations" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "停止 %@" + "value" : "运行/调试配置" } } } }, - "Stop All" : { + "Runs `make [-f ] [arguments]`. Leave Makefile empty to use the default lookup (Makefile / makefile / GNUmakefile)." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "全部停止" + "value" : "运行 `make [-f ] [arguments]`。留空 Makefile 会使用默认查找(Makefile / makefile / GNUmakefile)。" } } } }, - "Stop running tasks" : { + "Runs on-device with Apple Intelligence. Private, free, and offline." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "停止正在运行的任务" + "value" : "通过 Apple Intelligence 在设备端运行。私密、免费且离线。" } } } }, - "Stop streaming (cancel response generation)" : { - "extractionState" : "stale", + "RxCode" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Stop streaming (cancel response generation)" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "스트리밍 중지 (응답 생성 취소)" + "value" : "RxCode" } - }, + } + } + }, + "RxCode.xcodeproj" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "停止流式输出(取消响应生成)" + "value" : "RxCode.xcodeproj" } } } }, - "Strikethrough" : { - "extractionState" : "stale", + "rxcode/feature-name" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Strikethrough" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "취소선" + "value" : "rxcode/feature-name" } - }, + } + } + }, + "Save" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "删除线" + "value" : "保存" } } } }, - "Submit" : { + "Saved memories are stored locally in SwiftData and embedded on-device." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "提交" + "value" : "保存的记忆会存储在本地 SwiftData 中,并在设备端嵌入。" } } } }, - "Summarization Model" : { + "Saved memory history is available from Manage." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "摘要模型" + "value" : "可从“管理”查看已保存的记忆历史。" } } } }, - "Switch between Claude Code, Codex, and installed ACP agents without changing the global default." : { + "Saving and probing…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在 Claude Code、Codex 和已安装的 ACP 智能体之间切换,而不更改全局默认值。" + "value" : "正在保存并探测…" } } } }, - "Switch branch" : { + "Scan with the RxCode app on your iPhone or iPad." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换分支" + "value" : "使用 iPhone 或 iPad 上的 RxCode 应用扫描。" } } } }, - "Switch Branch" : { + "Scheme" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Switch Branch" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "브랜치 전환" + "value" : "Scheme" } - }, + } + } + }, + "Scope" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换分支" + "value" : "范围" } } } }, - "Tap to answer" : { - "comment" : "Notification body when Claude invokes AskUserQuestion.", + "Search agents" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "点击回答" + "value" : "搜索智能体" } } } }, - "Target" : { + "Search every thread" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "目标" + "value" : "搜索每个对话" } } } }, - "Terminal" : { - "extractionState" : "stale", + "Search filename..." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Terminal" + "value" : "Search filename..." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "터미널" + "value" : "파일 이름 검색..." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "终端" + "value" : "搜索文件名..." } } } }, - "Terminal Command Mode" : { - "extractionState" : "stale", + "Search Files (⌘F)" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Terminal Command Mode" + "value" : "Search Files (⌘F)" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "터미널 커맨드 모드" + "value" : "파일 검색 (⌘F)" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "终端命令模式" + "value" : "搜索文件 (⌘F)" + } + } + } + }, + "Search Index" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "搜索索引" } } } }, - "Terminal Tab" : { - "extractionState" : "stale", + "Search memory" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Terminal Tab" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "터미널 탭" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "终端标签页" + "value" : "搜索记忆" } } } }, - "Terminate the current shell and start a fresh zsh session" : { - "extractionState" : "stale", + "Search repos..." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Terminate the current shell and start a fresh zsh session" + "value" : "Search repos..." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "현재 셸을 종료하고 새 zsh 세션을 시작합니다" + "value" : "저장소 검색..." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "终止当前 shell 并启动新的 zsh 会话" + "value" : "搜索仓库..." } } } }, - "Terracotta" : { - "extractionState" : "stale", + "Search skills..." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Terracotta" + "value" : "Search skills..." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "테라코타" + "value" : "스킬 검색..." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "陶土" + "value" : "搜索技能..." } } } }, - "Test connection" : { + "Search Threads (⌘K)" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "测试连接" + "value" : "搜索对话(⌘K)" } } } }, - "Testing…" : { + "Search threads by topic, keyword, or feel…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "正在测试…" + "value" : "按主题、关键词或感觉搜索对话…" } } } }, - "The bar graph and percentage change color based on usage level." : { - "extractionState" : "stale", + "Select a Project" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "The bar graph and percentage change color based on usage level." + "value" : "Select a Project" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "막대 그래프와 퍼센트 수치는 사용량에 따라 색이 바뀝니다." + "value" : "프로젝트를 선택하세요" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "条形图和百分比会根据使用级别改变颜色。" + "value" : "选择项目" } } } }, - "The catalog refreshes automatically every 5 minutes." : { - "extractionState" : "stale", + "Select a project from the sidebar or add a new one." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "The catalog refreshes automatically every 5 minutes." + "value" : "Select a project from the sidebar or add a new one." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "카탈로그는 5분마다 자동으로 새로고침됩니다." + "value" : "사이드바에서 프로젝트를 선택하거나 새로 추가하세요." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "目录每 5 分钟自动刷新。" + "value" : "从侧边栏选择一个项目,或添加新项目。" } } } }, - "The CLI sent an AskUserQuestion call this app could not parse." : { + "Select a target…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "CLI 发送了此应用无法解析的 AskUserQuestion 调用。" + "value" : "选择目标…" } } } }, - "The exit code is shown at the bottom — \"exit 0\" means the command completed successfully." : { - "extractionState" : "stale", + "Select All in Section" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "The exit code is shown at the bottom — \"exit 0\" means the command completed successfully." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "하단에 종료 코드가 표시됩니다 — \"exit 0\"은 커맨드가 성공적으로 완료되었음을 의미합니다." + "value" : "选择本节全部" } - }, + } + } + }, + "Select all that apply" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "退出代码显示在底部;“exit 0”表示命令已成功完成。" + "value" : "选择所有适用项" } } } }, - "The General tab configures session defaults. Changes apply to newly created sessions — existing sessions keep their current values." : { - "extractionState" : "stale", + "Select Effort Level" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "The General tab configures session defaults. Changes apply to newly created sessions — existing sessions keep their current values." + "value" : "Select Effort Level" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "일반 탭에서 세션 기본값을 설정합니다. 변경사항은 새로 생성되는 세션에 적용되며, 기존 세션은 현재 값을 유지합니다." + "value" : "Effort 수준 선택" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "“通用”标签页配置会话默认值。更改会应用到新建会话;现有会话会保留当前值。" + "value" : "选择推理强度" } } } }, - "The Git status panel at the bottom of the sidebar shows changed-file counts and the current branch. Click the branch name to switch between local or remote branches." : { - "extractionState" : "stale", + "Select Model" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "The Git status panel at the bottom of the sidebar shows changed-file counts and the current branch. Click the branch name to switch between local or remote branches." + "value" : "Select Model" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "사이드바 하단의 Git 상태 패널에서 변경된 파일 수와 현재 브랜치를 확인할 수 있습니다. 브랜치 이름을 클릭하면 로컬 또는 원격 브랜치로 전환할 수 있습니다." + "value" : "모델 선택" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "边栏底部的 Git 状态面板显示已更改文件数量和当前分支。点击分支名称可在本地或远程分支之间切换。" + "value" : "选择模型" } } } }, - "The left sidebar has History and Files tabs. Project tabs appear at the top of the chat area — click to switch projects. The right inspector panel contains the Terminal and Memo tabs." : { - "extractionState" : "stale", + "Select or add a profile to edit" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "The left sidebar has History and Files tabs. Project tabs appear at the top of the chat area — click to switch projects. The right inspector panel contains the Terminal and Memo tabs." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "왼쪽 사이드바에는 기록 및 파일 탭이 있습니다. 채팅 영역 상단에 프로젝트 탭이 표시되며 클릭하여 전환할 수 있습니다. 오른쪽 인스펙터 패널에는 터미널과 메모 탭이 있습니다." + "value" : "选择或添加要编辑的配置" } - }, + } + } + }, + "Select relay" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "左侧边栏包含“历史”和“文件”标签页。项目标签页显示在聊天区域顶部,点击即可切换项目。右侧检查器面板包含“终端”和“备忘录”标签页。" + "value" : "选择中继" } } } }, - "The Message tab controls chat display and attachment behavior." : { - "extractionState" : "stale", + "Select Run Destination" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "The Message tab controls chat display and attachment behavior." + "state" : "translated", + "value" : "选择运行目标" } - }, - "ko" : { + } + } + }, + "Select Run Profile" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "메시지 탭에서 채팅 표시 및 첨부 파일 동작을 설정합니다." + "value" : "选择运行配置" } - }, + } + } + }, + "Send test notification" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "“消息”标签页控制聊天显示和附件行为。" + "value" : "发送测试通知" } } } }, - "The number of changed files is shown at the bottom of the sidebar." : { - "extractionState" : "stale", + "Sends a system notification while RxCode is in the background." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "The number of changed files is shown at the bottom of the sidebar." + "value" : "Sends a system notification while RxCode is in the background." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "변경된 파일 수가 사이드바 하단에 표시됩니다." + "value" : "RxCode가 백그라운드에 있을 때 시스템 알림을 보냅니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已更改文件数量显示在边栏底部。" + "value" : "当 RxCode 在后台时发送系统通知。" } } } }, - "The other two Settings tabs manage per-project slash commands and shortcut buttons. Slash command JSON import/export includes custom commands only; shortcut JSON import/export backs up the shortcut set." : { - "extractionState" : "stale", + "Servers" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "The other two Settings tabs manage per-project slash commands and shortcut buttons. Slash command JSON import/export includes custom commands only; shortcut JSON import/export backs up the shortcut set." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "另外两个设置标签页管理每个项目的斜杠命令和快捷按钮。斜杠命令的 JSON 导入/导出仅包含自定义命令;快捷按钮的 JSON 导入/导出会备份快捷按钮集。" + "value" : "服务器" } } } }, - "The Slash Commands tab manages built-in and custom commands — edit, enable/disable, add, or delete. JSON import/export covers custom commands only. The Shortcuts tab manages shortcut buttons with JSON import/export support." : { - "extractionState" : "stale", + "Session name" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "The Slash Commands tab manages built-in and custom commands — edit, enable/disable, add, or delete. JSON import/export covers custom commands only. The Shortcuts tab manages shortcut buttons with JSON import/export support." + "value" : "Session name" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "슬래시 커맨드 탭에서는 기본 및 커스텀 커맨드를 관리합니다 — 편집, 활성화/비활성화, 추가, 삭제가 가능합니다. JSON 가져오기/내보내기는 커스텀 커맨드만 지원합니다. 단축키 탭에서는 단축 버튼을 관리하며 JSON 가져오기/내보내기를 지원합니다." + "value" : "세션 이름" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "“斜杠命令”标签页管理内置和自定义命令:编辑、启用/禁用、添加或删除。JSON 导入/导出仅涵盖自定义命令。“快捷按钮”标签页管理快捷按钮,并支持 JSON 导入/导出。" + "value" : "会话名称" } } } }, - "The toolbar contains: New Chat, Manage Slash Commands, Manage Shortcut Buttons, Skip Permissions toggle, Model picker, Inspector panel toggle, Settings, and the GitHub integration button." : { - "extractionState" : "stale", + "Set the summarization model" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "The toolbar contains: New Chat, Manage Slash Commands, Manage Shortcut Buttons, Skip Permissions toggle, Model picker, Inspector panel toggle, Settings, and the GitHub integration button." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "툴바 구성: 새 채팅, 슬래시 커맨드 관리, 단축 버튼 관리, 권한 건너뛰기 토글, 모델 선택, 인스펙터 패널 토글, 설정, GitHub 연동 버튼." + "value" : "设置摘要模型" } - }, + } + } + }, + "Settings" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "工具栏包含:新聊天、管理斜杠命令、管理快捷按钮、跳过权限开关、模型选择器、检查器面板开关、设置和 GitHub 集成按钮。" + "value" : "设置" } } } }, - "Theme" : { + "Shortcuts" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Theme" + "value" : "Shortcuts" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "테마" + "value" : "단축키" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "主题" + "value" : "快捷方式" } } } }, - "Themes" : { - "extractionState" : "stale", + "Show active chats" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Themes" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "테마" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "主题" + "value" : "显示活跃聊天" } } } }, - "There are no tasks to run %@." : { + "Show all chats" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "没有可运行 %@ 的任务。" + "value" : "显示所有聊天" } } } }, - "This agent didn't advertise a model selector. The model picker shows a single \"Default\" entry — the agent picks its own model at runtime. Click Fetch to retry." : { + "Show all projects" : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Show all projects" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "모든 프로젝트 표시" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "此智能体未声明模型选择器。模型选择器只显示一个“默认”项,智能体会在运行时自行选择模型。点击“获取”重试。" + "value" : "显示所有项目" } } } }, - "This agent reports its models over ACP. RxCode refreshes the list every session start." : { + "Show all threads in this project" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "此智能体通过 ACP 报告模型。RxCode 会在每次会话开始时刷新列表。" + "value" : "显示此项目中的所有对话" } } } }, - "This memory will be removed from future agent context." : { + "Show archived chats" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "此记忆将从后续智能体上下文中移除。" + "value" : "显示已归档聊天" } } } }, - "This project" : { + "Show current project only" : { "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Show current project only" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "현재 프로젝트만 표시" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "此项目" + "value" : "仅显示当前项目" } } } }, - "This session will be deleted. This action cannot be undone." : { + "Show Hidden Files" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "此会话将被删除。此操作无法撤销。" + "value" : "显示隐藏文件" } } } }, - "This will remove the project from RxCode. The files on disk will not be deleted." : { + "Show in Finder" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "This will remove the project from RxCode. The files on disk will not be deleted." + "value" : "Show in Finder" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "RxCode에서 프로젝트가 제거됩니다. 디스크의 파일은 삭제되지 않습니다." + "value" : "Finder에서 보기" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "这会从 RxCode 中移除该项目。磁盘上的文件不会被删除。" + "value" : "在 Finder 中显示" } } } }, - "Thread Model" : { - + "Show menu bar icon" : { + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "显示菜单栏图标" + } + } + } }, - "Threads" : { + "Show more" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "对话" + "value" : "显示更多" } } } }, - "Todos (%lld/%lld)" : { + "Show Onboarding" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Todos (%1$lld/%2$lld)" + "state" : "translated", + "value" : "显示入门引导" } - }, + } + } + }, + "Show only the first five threads" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "待办(%1$lld/%2$lld)" + "value" : "仅显示前五个对话" } } } }, - "Toggle checkbox" : { - "extractionState" : "stale", + "Show thread summary" : { "localizations" : { - "en" : { + "zh-Hans" : { "stringUnit" : { - "state" : "new", - "value" : "Toggle checkbox" + "state" : "translated", + "value" : "显示对话摘要" } - }, - "ko" : { + } + } + }, + "Showing effective MCP state for this project" : { + "localizations" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "체크박스 토글" + "value" : "显示此项目的有效 MCP 状态" } - }, + } + } + }, + "Showing global MCP defaults" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换复选框" + "value" : "显示全局 MCP 默认值" } } } }, - "Toggle Inspector" : { + "Shows in-progress chat counts and Claude Code usage limits in the macOS menu bar." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换检查器" + "value" : "在 macOS 菜单栏中显示进行中的聊天数量和 Claude Code 用量限制。" } } } }, - "Toggle left sidebar" : { - "extractionState" : "stale", + "Sign in with GitHub" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Toggle left sidebar" + "value" : "Sign in with GitHub" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "왼쪽 사이드바 펼치기/숨기기" + "value" : "GitHub로 로그인" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换左侧边栏" + "value" : "使用 GitHub 登录" } } } }, - "Toggle right inspector panel" : { - "extractionState" : "stale", + "sk-..." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Toggle right inspector panel" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "오른쪽 인스펙터 패널 펼치기/숨기기" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换右侧检查器面板" + "value" : "sk-..." } } } }, - "Toggle the eye icon in the Files tab header to show or hide dotfiles (files starting with a period, such as .env or .gitignore)." : { - "extractionState" : "stale", + "Skill Marketplace" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Toggle the eye icon in the Files tab header to show or hide dotfiles (files starting with a period, such as .env or .gitignore)." + "value" : "Skill Marketplace" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "파일 탭 헤더의 눈 아이콘을 토글하여 점(.)으로 시작하는 파일(예: .env, .gitignore)의 표시 여부를 전환할 수 있습니다." + "value" : "스킬 마켓플레이스" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换“文件”标签页标题栏中的眼睛图标,以显示或隐藏点文件(以句点开头的文件,如 .env 或 .gitignore)。" + "value" : "技能市场" } } } }, - "Toggle the shield icon at the top of the chat to auto-approve all permission prompts. Use with caution." : { - "extractionState" : "stale", + "Skip All Questions" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Toggle the shield icon at the top of the chat to auto-approve all permission prompts. Use with caution." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "채팅 상단의 방패 아이콘을 토글하면 모든 권한 요청이 자동으로 승인됩니다. 주의해서 사용하세요." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换聊天顶部的盾牌图标,以自动批准所有权限提示。请谨慎使用。" + "value" : "跳过所有问题" } } } }, - "Toggle the shield icon at the top of the chat to auto-approve all permission requests. This speeds up tasks but also auto-executes potentially dangerous operations — use with caution." : { - "extractionState" : "stale", + "Slash Commands" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Toggle the shield icon at the top of the chat to auto-approve all permission requests. This speeds up tasks but also auto-executes potentially dangerous operations — use with caution." + "value" : "Slash Commands" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "채팅 상단의 방패 아이콘을 토글하면 모든 권한 요청이 자동으로 승인됩니다. 작업 속도는 빨라지지만 잠재적으로 위험한 작업도 자동 실행되므로 주의해서 사용하세요." + "value" : "슬래시 커맨드" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "切换聊天顶部的盾牌图标,以自动批准所有权限请求。这会加快任务速度,但也会自动执行潜在危险操作,请谨慎使用。" + "value" : "斜杠命令" } } } }, - "Top Toolbar" : { - "extractionState" : "stale", + "Source" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Top Toolbar" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "상단 툴바" + "value" : "来源" } - }, + } + } + }, + "Start New Chat" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "顶部工具栏" + "value" : "开始新聊天" } } } }, - "Total response time — cumulative time Claude spent generating responses in this session" : { - "extractionState" : "stale", + "Stop '%@'" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Total response time — cumulative time Claude spent generating responses in this session" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "총 응답 시간 — 현재 세션에서 Claude가 응답하는 데 걸린 시간의 합계" + "value" : "停止“%@”" } - }, + } + } + }, + "Stop %@" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "总响应时间 — Claude 在当前会话中生成响应所花费的累计时间" + "value" : "停止 %@" } } } }, - "Transport" : { + "Stop All" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "传输" + "value" : "全部停止" } } } }, - "Type" : { + "Stop running tasks" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "类型" + "value" : "停止正在运行的任务" } } } }, - "Type @ in the input field to open a project file search popup. Files are filtered in real time as you type." : { - "extractionState" : "stale", + "Submit" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Type @ in the input field to open a project file search popup. Files are filtered in real time as you type." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "입력창에 @를 입력하면 프로젝트 파일 검색 팝업이 열립니다. 입력할수록 실시간으로 필터링됩니다." + "value" : "提交" } - }, + } + } + }, + "Summarization Model" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在输入框中输入 @ 可打开项目文件搜索弹出框。输入时文件会实时筛选。" + "value" : "摘要模型" } } } }, - "Type / in the input field to open a popup list of available commands. Slash commands let you quickly trigger Claude Code CLI operations without typing them manually." : { - "extractionState" : "stale", + "Switch between Claude Code, Codex, and installed ACP agents without changing the global default." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Type / in the input field to open a popup list of available commands. Slash commands let you quickly trigger Claude Code CLI operations without typing them manually." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "입력창에 /를 입력하면 사용 가능한 커맨드 팝업 목록이 열립니다. 슬래시 커맨드를 사용하면 Claude Code CLI 작업을 빠르게 실행할 수 있습니다." + "value" : "在 Claude Code、Codex 和已安装的 ACP 智能体之间切换,而不更改全局默认值。" } - }, + } + } + }, + "Switch branch" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在输入框中输入 / 可打开可用命令弹出列表。斜杠命令可让你快速触发 Claude Code CLI 操作,无需手动输入。" + "value" : "切换分支" } } } }, - "Type / to open the popup, then continue typing to filter results. Use ↑/↓ to navigate." : { - "extractionState" : "stale", + "Switch Branch" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Type / to open the popup, then continue typing to filter results. Use ↑/↓ to navigate." + "value" : "Switch Branch" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "/를 입력하여 팝업을 열고 계속 입력하면 결과가 필터링됩니다. ↑/↓로 탐색하세요." + "value" : "브랜치 전환" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "输入 / 打开弹出框,然后继续输入以筛选结果。使用 ↑/↓ 导航。" + "value" : "切换分支" } } } }, - "Type a message in the input field and press Return or the send button." : { - "extractionState" : "stale", + "Tap to answer" : { + "comment" : "Notification body when Claude invokes AskUserQuestion.", "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Type a message in the input field and press Return or the send button." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력창에 메시지를 입력하고 Return 키 또는 전송 버튼을 누르세요." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在输入框中输入消息,然后按 Return 或发送按钮。" + "value" : "点击回答" } } } }, - "Type your answer…" : { + "Target" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "输入你的回答…" + "value" : "目标" } } } }, - "Unable to load files" : { - "extractionState" : "stale", + "Test connection" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Unable to load files" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "파일을 불러올 수 없습니다" + "value" : "测试连接" } - }, + } + } + }, + "Testing…" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "无法加载文件" + "value" : "正在测试…" } } } }, - "Unarchive" : { + "The CLI sent an AskUserQuestion call this app could not parse." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "取消归档" + "value" : "CLI 发送了此应用无法解析的 AskUserQuestion 调用。" } } } }, - "Underline" : { - "extractionState" : "stale", + "Theme" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Underline" + "value" : "Theme" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "밑줄" + "value" : "테마" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "下划线" + "value" : "主题" } } } }, - "Unordered list (auto-continues on Return)" : { - "extractionState" : "stale", + "There are no tasks to run %@." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Unordered list (auto-continues on Return)" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "순서 없는 목록 (Return 시 자동 계속)" + "value" : "没有可运行 %@ 的任务。" } - }, + } + } + }, + "This agent didn't advertise a model selector. The model picker shows a single \"Default\" entry — the agent picks its own model at runtime. Click Fetch to retry." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "无序列表(按 Return 自动延续)" + "value" : "此智能体未声明模型选择器。模型选择器只显示一个“默认”项,智能体会在运行时自行选择模型。点击“获取”重试。" } } } }, - "Unpin" : { + "This agent reports its models over ACP. RxCode refreshes the list every session start." : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Unpin" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "고정 해제" + "value" : "此智能体通过 ACP 报告模型。RxCode 会在每次会话开始时刷新列表。" } - }, + } + } + }, + "This memory will be removed from future agent context." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "取消固定" + "value" : "此记忆将从后续智能体上下文中移除。" } } } }, - "Updated %@" : { + "This project" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "已更新 %@" + "value" : "此项目" } } } }, - "URL" : { + "This session will be deleted. This action cannot be undone." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "此会话将被删除。此操作无法撤销。" } } } }, - "URL → attached as a URL reference" : { - "extractionState" : "stale", + "This will remove the project from RxCode. The files on disk will not be deleted." : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "URL → attached as a URL reference" + "value" : "This will remove the project from RxCode. The files on disk will not be deleted." } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "URL → URL 참조로 첨부" + "value" : "RxCode에서 프로젝트가 제거됩니다. 디스크의 파일은 삭제되지 않습니다." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "URL → 作为 URL 引用附加" + "value" : "这会从 RxCode 中移除该项目。磁盘上的文件不会被删除。" } } } }, - "URL links" : { + "Thread Model" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "URL links" - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "URL 링크" + "value" : "对话模型" } - }, + } + } + }, + "Threads" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "URL 链接" + "value" : "对话" } } } }, - "Usage Colors" : { - "extractionState" : "stale", + "Todos (%lld/%lld)" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Usage Colors" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "사용량 색상" + "value" : "Todos (%1$lld/%2$lld)" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "用量颜色" + "value" : "待办(%1$lld/%2$lld)" } } } }, - "Usage data refreshes automatically after each response. If the initial fetch fails on launch, it retries once after 5 seconds." : { - "extractionState" : "stale", + "Toggle Inspector" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Usage data refreshes automatically after each response. If the initial fetch fails on launch, it retries once after 5 seconds." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "사용량 정보는 응답이 완료될 때마다 자동으로 갱신됩니다. 앱 시작 시 초기 조회에 실패하면 5초 후 한 번 재시도합니다." + "value" : "切换检查器" } - }, + } + } + }, + "Transport" : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "用量数据会在每次响应后自动刷新。如果启动时首次获取失败,会在 5 秒后重试一次。" + "value" : "传输" } } } }, - "Use a GitHub repository that exposes .claude-plugin/marketplace.json." : { + "Type" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用暴露 .claude-plugin/marketplace.json 的 GitHub 仓库。" + "value" : "类型" } } } }, - "Use default Makefile lookup" : { + "Type your answer…" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用默认 Makefile 查找" + "value" : "输入你的回答…" } } } }, - "Use hosted relay" : { + "Unarchive" : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用托管中继" + "value" : "取消归档" } } } }, - "Use the effort dropdown next to the model picker to control how much reasoning Claude applies. The selection is per-session." : { - "extractionState" : "stale", + "Unpin" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Use the effort dropdown next to the model picker to control how much reasoning Claude applies. The selection is per-session." + "value" : "Unpin" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "모델 선택기 옆의 작업량 드롭다운에서 Claude가 사용할 추론 강도를 조절할 수 있습니다. 선택값은 세션별로 저장됩니다." + "value" : "고정 해제" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用模型选择器旁边的推理强度下拉菜单来控制 Claude 使用多少推理。该选择按会话保存。" + "value" : "取消固定" } } } }, - "Use the model dropdown at the top of the chat area to switch Claude models." : { - "extractionState" : "stale", + "Updated %@" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Use the model dropdown at the top of the chat area to switch Claude models." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "채팅 영역 상단의 모델 드롭다운을 사용하여 Claude 모델을 전환하세요." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用聊天区域顶部的模型下拉菜单切换 Claude 模型。" + "value" : "已更新 %@" } } } }, - "Use the permission mode dropdown at the top of the chat to control how Claude requests approval before running actions." : { - "extractionState" : "stale", + "URL" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Use the permission mode dropdown at the top of the chat to control how Claude requests approval before running actions." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "채팅 상단의 권한 모드 드롭다운에서 Claude가 작업 전에 승인을 요청하는 방식을 제어할 수 있습니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用聊天顶部的权限模式下拉菜单控制 Claude 在运行操作前如何请求批准。" + "value" : "URL" } } } }, - "Use the permission mode dropdown at the top of the chat to switch how Claude handles permissions." : { - "extractionState" : "stale", + "URL links" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Use the permission mode dropdown at the top of the chat to switch how Claude handles permissions." + "value" : "URL links" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "채팅 상단의 권한 모드 드롭다운에서 Claude의 권한 처리 방식을 전환할 수 있습니다." + "value" : "URL 링크" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用聊天顶部的权限模式下拉菜单切换 Claude 处理权限的方式。" + "value" : "URL 链接" } } } }, - "Use the registry to add Agent Client Protocol tools, then pick them from the thread model menu." : { + "Use a GitHub repository that exposes .claude-plugin/marketplace.json." : { "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用注册表添加 Agent Client Protocol 工具,然后从对话模型菜单中选择。" + "value" : "使用暴露 .claude-plugin/marketplace.json 的 GitHub 仓库。" } } } }, - "Use the toolbar at the bottom for formatting, or the keyboard shortcuts below." : { - "extractionState" : "stale", + "Use default Makefile lookup" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Use the toolbar at the bottom for formatting, or the keyboard shortcuts below." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "하단 툴바를 사용하거나 아래 단축키로 서식을 지정할 수 있습니다." - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用底部工具栏进行格式设置,或使用下面的键盘快捷键。" + "value" : "使用默认 Makefile 查找" } } } }, - "Use the trash icon in the History header to delete all sessions at once." : { - "extractionState" : "stale", + "Use hosted relay" : { "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Use the trash icon in the History header to delete all sessions at once." - } - }, - "ko" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "기록 헤더의 휴지통 아이콘을 사용하면 모든 세션을 한 번에 삭제할 수 있습니다." + "value" : "使用托管中继" } - }, + } + } + }, + "Use the registry to add Agent Client Protocol tools, then pick them from the thread model menu." : { + "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "使用“历史”标题栏中的废纸篓图标可一次删除所有会话。" + "value" : "使用注册表添加 Agent Client Protocol 工具,然后从对话模型菜单中选择。" } } } @@ -13776,29 +7204,6 @@ } } }, - "View command details" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "View command details" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "커맨드 상세 보기" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "查看命令详情" - } - } - } - }, "View details" : { "localizations" : { "zh-Hans" : { @@ -13831,167 +7236,6 @@ } } }, - "Warm yellow" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Warm yellow" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "따뜻한 옐로우" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "暖黄色" - } - } - } - }, - "What are Permission Requests?" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What are Permission Requests?" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "권한 요청이란?" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "什么是权限请求?" - } - } - } - }, - "What are Shortcut Buttons?" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What are Shortcut Buttons?" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "단축 버튼이란?" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "什么是快捷按钮?" - } - } - } - }, - "What are Slash Commands?" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What are Slash Commands?" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "슬래시 커맨드란?" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "什么是斜杠命令?" - } - } - } - }, - "What is RxCode?" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What is RxCode?" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "RxCode란?" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "什么是 RxCode?" - } - } - } - }, - "What is the Status Line?" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "What is the Status Line?" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "상태 표시줄이란?" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "什么是状态行?" - } - } - } - }, - "When the input field is empty, use ↑/↓ to navigate your message history." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "When the input field is empty, use ↑/↓ to navigate your message history." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "입력창이 비어 있을 때 ↑/↓를 눌러 메시지 기록을 탐색할 수 있습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "输入框为空时,使用 ↑/↓ 浏览消息历史。" - } - } - } - }, "Wipe cached embeddings and re-embed every thread for semantic search. Use this if global search results look stale or empty." : { "localizations" : { "zh-Hans" : { @@ -14032,29 +7276,6 @@ } } }, - "XHigh" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "XHigh" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "매우 높음" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "极高" - } - } - } - }, "You" : { "localizations" : { "zh-Hans" : { @@ -14064,29 +7285,6 @@ } } } - }, - "You can send messages even while Claude is responding. New messages are queued automatically and sent once the current response finishes. Queued messages appear as a badge above the input field — click the × on each item to remove it from the queue." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "You can send messages even while Claude is responding. New messages are queued automatically and sent once the current response finishes. Queued messages appear as a badge above the input field — click the × on each item to remove it from the queue." - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "Claude가 응답하는 동안에도 메시지를 전송할 수 있습니다. 새 메시지는 자동으로 큐에 추가되고 현재 응답이 완료되면 전송됩니다. 대기 중인 메시지는 입력창 위에 배지로 표시되며, 각 항목의 × 버튼으로 제거할 수 있습니다." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "即使 Claude 正在响应,你也可以发送消息。新消息会自动排队,并在当前响应完成后发送。排队消息会以徽标显示在输入框上方;点击每项上的 × 可将其从队列中移除。" - } - } - } } }, "version" : "1.1" diff --git a/RxCode/Services/MobileSyncService+EventDispatch.swift b/RxCode/Services/MobileSyncService+EventDispatch.swift index 6d6a4b79..c1e384ab 100644 --- a/RxCode/Services/MobileSyncService+EventDispatch.swift +++ b/RxCode/Services/MobileSyncService+EventDispatch.swift @@ -17,8 +17,13 @@ extension MobileSyncService { logger.info("[MobileSync] relay state=\(String(describing: s), privacy: .public) relay=\(self.relayURL.absoluteString, privacy: .public)") case .deliveryFailed(let toHex): // Drop-on-offline policy — desktop ignores, mobile will resync on - // next reconnect. - logger.warning("[MobileSync] relay delivery failed to mobileKey=\(String(toHex.prefix(12)), privacy: .public)") + // next reconnect. Warn only on the online → offline transition so + // probe pings to a still-offline device don't spam the log. + if markPeerOffline(toHex) { + logger.warning("[MobileSync] relay delivery failed to mobileKey=\(String(toHex.prefix(12)), privacy: .public)") + } else { + logger.debug("[MobileSync] relay delivery failed (already offline) mobileKey=\(String(toHex.prefix(12)), privacy: .public)") + } case .inbound(let inbound): handleInbound(inbound) } @@ -33,7 +38,11 @@ extension MobileSyncService { updateAggregateConnectionState() logger.info("[MobileSync] relay state=\(String(describing: s), privacy: .public) server=\(server.name, privacy: .public)") case .deliveryFailed(let toHex): - logger.warning("[MobileSync] relay delivery failed to mobileKey=\(String(toHex.prefix(12)), privacy: .public) server=\(server.name, privacy: .public)") + if markPeerOffline(toHex) { + logger.warning("[MobileSync] relay delivery failed to mobileKey=\(String(toHex.prefix(12)), privacy: .public) server=\(server.name, privacy: .public)") + } else { + logger.debug("[MobileSync] relay delivery failed (already offline) mobileKey=\(String(toHex.prefix(12)), privacy: .public) server=\(server.name, privacy: .public)") + } case .inbound(let inbound): handleInbound(inbound, fromServer: server) } @@ -74,6 +83,10 @@ extension MobileSyncService { private func handleInbound(_ inbound: RelayClient.Inbound, viaClient: SyncClient?) { let activeClient = viaClient ?? client + // Any decrypted inbound proves the peer is currently reachable on the + // relay socket. Flip the cached online state so the next broadcast + // goes back through the live channel. + markPeerOnline(inbound.fromHex) switch inbound.payload { case .pairRequest(let req): pendingPairing = req diff --git a/RxCode/Services/MobileSyncService.swift b/RxCode/Services/MobileSyncService.swift index 62bb6dc6..5befb8b4 100644 --- a/RxCode/Services/MobileSyncService.swift +++ b/RxCode/Services/MobileSyncService.swift @@ -13,6 +13,15 @@ struct LiveActivityTokenRef: Codable, Sendable, Hashable { var token: String } +/// Whether a paired mobile is currently reachable via the relay socket. +/// Resolved reactively from relay traffic — `unknown` until the first +/// inbound payload or `delivery_failed` notice settles it. +enum OnlineState: Sendable, Hashable { + case unknown + case online + case offline +} + /// One paired mobile device. Persisted to /// `~/Library/Application Support/RxCode/paired_devices.json`. struct PairedDevice: Codable, Identifiable, Sendable, Hashable { @@ -32,6 +41,12 @@ struct PairedDevice: Codable, Identifiable, Sendable, Hashable { /// The relay server URL this device was paired through. var relayURL: String? + /// Reactive online presence — not persisted. Always starts `.unknown` on + /// launch; the first inbound/`delivery_failed` after `start()` resolves it. + var onlineState: OnlineState = .unknown + /// Wall-clock of the last `onlineState` change. Not persisted. + var lastOnlineTransitionAt: Date? = nil + var id: String { pubkeyHex } /// Human-readable relay host for display (e.g. "relay.example.com"). @@ -41,6 +56,22 @@ struct PairedDevice: Codable, Identifiable, Sendable, Hashable { let host = url.host else { return nil } return host } + + // Persist only the long-lived fields — runtime presence (`onlineState`, + // `lastOnlineTransitionAt`) is intentionally excluded so a launch always + // begins in `.unknown` rather than restoring a possibly-stale value. + enum CodingKeys: String, CodingKey { + case pubkeyHex + case displayName + case platform + case apnsToken + case apnsEnvironment + case liveActivityStartToken + case liveActivityTokens + case pairedAt + case lastSeen + case relayURL + } } /// Result of a pairing handshake propagated to the SwiftUI pairing sheet. @@ -129,6 +160,12 @@ final class MobileSyncService: ObservableObject { var additionalEventTasks: [UUID: Task] = [:] var subscribedSessions: [String: String] = [:] var eventTask: Task? + /// Periodically pings paired peers we believe to be offline so an idle + /// mobile that has come back online is detected without waiting for it to + /// send something inbound. Started in `start()`, cancelled in `stop()`. + var presenceProbeTask: Task? + /// Spacing between probe pings. One ping per offline peer per tick. + static let presenceProbeInterval: TimeInterval = 60 var pairingToken: PairingToken? var pairingContinuation: CheckedContinuation? /// The relay server ID currently being used for pairing. @@ -224,6 +261,7 @@ final class MobileSyncService: ObservableObject { logger.info("[MobileSync] no relay servers configured — waiting for user to add one") } } + startPresenceProbeLoop() } /// Start connection to a specific relay server. @@ -317,6 +355,8 @@ final class MobileSyncService: ObservableObject { eventTask = nil pendingJobsPushTask?.cancel() pendingJobsPushTask = nil + presenceProbeTask?.cancel() + presenceProbeTask = nil // Stop all relay server connections for (serverID, task) in additionalEventTasks { @@ -389,7 +429,7 @@ final class MobileSyncService: ObservableObject { let pairingClient = pairingRelayServerID.flatMap { additionalClients[$0] } let relayURLString = pairingServer?.url ?? pairingToken?.relayURL ?? "" - let device = PairedDevice( + var device = PairedDevice( pubkeyHex: pending.mobilePubkeyHex, displayName: pending.displayName, platform: pending.platform, @@ -399,6 +439,9 @@ final class MobileSyncService: ObservableObject { lastSeen: .now, relayURL: relayURLString ) + // The mobile just completed a live pairing handshake — it is online. + device.onlineState = .online + device.lastOnlineTransitionAt = .now pairedDevices.removeAll { $0.pubkeyHex == device.pubkeyHex } pairedDevices.append(device) savePairedDevices() @@ -466,10 +509,15 @@ final class MobileSyncService: ObservableObject { // MARK: - Notification fan-out - /// Broadcast a message to all connected relay clients. + /// Broadcast a message to all paired mobile peers that are not known to be + /// offline. Peers in `.unknown` state are still attempted (default-open) so + /// the very first send after launch isn't suppressed. Peers in `.offline` + /// are skipped on the relay socket; APNs fan-out runs separately and is + /// not gated here. private func broadcastToAllClients(_ payload: RxCodeSync.Payload) async { - for client in additionalClients.values { - await client.broadcast(payload) + for device in pairedDevices where device.onlineState != .offline { + let target = clientForPeer(device.pubkeyHex) + try? await target.send(payload, toHex: device.pubkeyHex) } } @@ -680,6 +728,62 @@ final class MobileSyncService: ObservableObject { } } + // MARK: - Online presence + + /// Mark a paired peer as online. Returns true if this changed the state + /// (so callers can suppress per-event logging on repeats). Unknown peers + /// are ignored. + @discardableResult + func markPeerOnline(_ pubkeyHex: String) -> Bool { + guard let idx = pairedDevices.firstIndex(where: { $0.pubkeyHex == pubkeyHex }) else { + return false + } + if pairedDevices[idx].onlineState == .online { return false } + pairedDevices[idx].onlineState = .online + pairedDevices[idx].lastOnlineTransitionAt = .now + return true + } + + /// Mark a paired peer as offline. Returns true if this changed the state + /// (so the caller can warn once on the online → offline transition and + /// stay quiet on repeats). + @discardableResult + func markPeerOffline(_ pubkeyHex: String) -> Bool { + guard let idx = pairedDevices.firstIndex(where: { $0.pubkeyHex == pubkeyHex }) else { + return false + } + if pairedDevices[idx].onlineState == .offline { return false } + pairedDevices[idx].onlineState = .offline + pairedDevices[idx].lastOnlineTransitionAt = .now + return true + } + + private func startPresenceProbeLoop() { + presenceProbeTask?.cancel() + presenceProbeTask = Task { @MainActor [weak self] in + let interval = UInt64(Self.presenceProbeInterval * 1_000_000_000) + while !Task.isCancelled { + try? await Task.sleep(nanoseconds: interval) + guard !Task.isCancelled else { return } + await self?.probeOfflinePeers() + } + } + } + + /// Send a `ping` to every peer currently marked offline. If the peer is + /// in fact reachable it will reply with `pong`, the inbound path flips + /// `onlineState` back to `.online`, and the next broadcast goes through. + /// If the peer is still offline the relay returns `delivery_failed` and + /// we stay quietly offline (no warning, since the transition already + /// fired). + func probeOfflinePeers() async { + let targets = pairedDevices.filter { $0.onlineState == .offline } + for device in targets { + let target = clientForPeer(device.pubkeyHex) + try? await target.send(.ping(PingPayload()), toHex: device.pubkeyHex) + } + } + // MARK: - Persistence var pairedDevicesURL: URL { diff --git a/RxCode/Services/ThreadStore.swift b/RxCode/Services/ThreadStore.swift index cf0a416e..17155bc4 100644 --- a/RxCode/Services/ThreadStore.swift +++ b/RxCode/Services/ThreadStore.swift @@ -266,6 +266,19 @@ final class ThreadStore { return row.toSummary() } + /// Return the ids of archived, non-pinned threads whose `archivedAt` is older + /// than `cutoff`. Caller is responsible for routing each id through the full + /// delete path (persistence + search service + SwiftData) — see `AppState`. + func staleArchivedIds(olderThan cutoff: Date) -> [String] { + let descriptor = FetchDescriptor( + predicate: #Predicate { row in + row.isArchived == true && row.isPinned == false && row.archivedAt != nil && row.archivedAt! < cutoff + } + ) + let rows = (try? context.fetch(descriptor)) ?? [] + return rows.map(\.id) + } + /// Archive all non-pinned, non-archived threads whose `updatedAt` is older than /// `cutoff`. Returns the ids that were archived. func archiveStale(olderThan cutoff: Date, now: Date = .now) -> [String] { @@ -496,12 +509,18 @@ final class ThreadStore { /// to this path within this session. It's stored only on row creation — /// subsequent calls preserve the original snapshot rather than overwriting /// it, so the diff view always compares against the true thread-start state. + /// + /// `modifiedContent` is the file's contents re-read from disk immediately + /// after the tool_result. Unlike `originalContent` it is **always + /// overwritten** on subsequent edits so the "after" side reflects this + /// thread's most recent committed state. func appendFileEdit( sessionId: String, path: String, hunks: [PreviewFile.EditHunk], containsWrite: Bool, - originalContent: String? = nil + originalContent: String? = nil, + modifiedContent: String? = nil ) { guard !hunks.isEmpty else { return } let name = (path as NSString).lastPathComponent @@ -511,6 +530,7 @@ final class ThreadStore { if existing.originalContent == nil, let originalContent { existing.originalContent = originalContent } + existing.modifiedContent = modifiedContent } else { context.insert(ThreadFileEdit( sessionId: sessionId, @@ -518,7 +538,8 @@ final class ThreadStore { name: name, hunks: hunks, containsWrite: containsWrite, - originalContent: originalContent + originalContent: originalContent, + modifiedContent: modifiedContent )) } save() diff --git a/RxCode/Views/Chat/BranchPickerChip.swift b/RxCode/Views/Chat/BranchPickerChip.swift index f54cd37b..f8f72607 100644 --- a/RxCode/Views/Chat/BranchPickerChip.swift +++ b/RxCode/Views/Chat/BranchPickerChip.swift @@ -13,8 +13,33 @@ struct BranchPickerChip: View { @State private var branches: [String] = [] @State private var switchingTo: String? @State private var refreshTask: Task? + @State private var isInitializingGit = false var body: some View { + Group { + if shouldShowInitGit { + initGitButton + } else { + branchMenu + } + } + .help(workingDirectoryHint) + .sheet(isPresented: $showCreateSheet) { + CreateBranchSheet(currentBranch: currentBranch) { + refresh() + } + } + .task(id: refreshKey) { + await refreshNow() + } + .onChange(of: refreshKey) { _, _ in refresh() } + } + + private var shouldShowInitGit: Bool { + sessionWorktreeBranch == nil && currentBranch == nil + } + + private var branchMenu: some View { Menu { if !branches.isEmpty { Section("Switch branch") { @@ -59,16 +84,42 @@ struct BranchPickerChip: View { .menuStyle(.borderlessButton) .menuIndicator(.hidden) .fixedSize() - .help(workingDirectoryHint) - .sheet(isPresented: $showCreateSheet) { - CreateBranchSheet(currentBranch: currentBranch) { - refresh() + } + + private var initGitButton: some View { + Button { + initializeGit() + } label: { + HStack(spacing: 4) { + if isInitializingGit { + ProgressView().controlSize(.mini) + } else { + Image(systemName: "plus.circle") + .font(.system(size: ClaudeTheme.size(10))) + } + Text(isInitializingGit ? "Initializing…" : "Initialize Git") + .font(.system(size: ClaudeTheme.size(12), weight: .medium)) + .lineLimit(1) } + .foregroundStyle(ClaudeTheme.textSecondary) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(ClaudeTheme.surfaceSecondary, in: RoundedRectangle(cornerRadius: ClaudeTheme.cornerRadiusSmall)) } - .task(id: refreshKey) { - await refreshNow() + .buttonStyle(.plain) + .fixedSize() + .disabled(isInitializingGit) + } + + private func initializeGit() { + guard !isInitializingGit else { return } + guard let path = sessionWorktreePath ?? windowState.selectedProject?.path else { return } + isInitializingGit = true + Task { + _ = await GitHelper.initRepository(at: path) + isInitializingGit = false + refresh() } - .onChange(of: refreshKey) { _, _ in refresh() } } private var activeBranch: String? { @@ -115,7 +166,7 @@ struct BranchPickerChip: View { private var displayName: String { if let b = sessionWorktreeBranch { return b } if let b = currentBranch { return b } - return "Work locally" + return "" } private var workingDirectoryHint: String { diff --git a/RxCode/Views/ChatSettingsTab.swift b/RxCode/Views/ChatSettingsTab.swift index 8b082b5a..21ac508f 100644 --- a/RxCode/Views/ChatSettingsTab.swift +++ b/RxCode/Views/ChatSettingsTab.swift @@ -28,6 +28,8 @@ struct ChatSettingsTab: View { autoPreviewSection Divider() archiveSection + Divider() + autoDeleteSection } .padding(24) .frame(maxWidth: .infinity, alignment: .leading) @@ -161,6 +163,42 @@ struct ChatSettingsTab: View { } } + // MARK: - Auto-Delete Section + + private var autoDeleteSection: some View { + @Bindable var appState = appState + return VStack(alignment: .leading, spacing: 12) { + Text("Auto-delete") + .font(.system(size: ClaudeTheme.size(13), weight: .semibold)) + + Text("Permanently delete archived chats after the retention window. Pinned chats are never auto-deleted. This cannot be undone.") + .font(.system(size: ClaudeTheme.size(11))) + .foregroundStyle(.secondary) + + Toggle(isOn: $appState.autoDeleteEnabled) { + Text("Auto-delete archived chats") + } + .toggleStyle(.switch) + .fixedSize() + + HStack(spacing: 10) { + Text("Delete after") + .font(.system(size: ClaudeTheme.size(12))) + .foregroundStyle(.secondary) + Stepper( + value: $appState.deleteRetentionDays, + in: 1...365 + ) { + Text("\(appState.deleteRetentionDays) day\(appState.deleteRetentionDays == 1 ? "" : "s") after archiving") + .font(.system(size: ClaudeTheme.size(13), weight: .medium)) + } + .fixedSize() + } + .disabled(!appState.autoDeleteEnabled) + .opacity(appState.autoDeleteEnabled ? 1 : 0.5) + } + } + // MARK: - Model Section private var modelSection: some View { diff --git a/RxCode/Views/Inspector/ThisThreadDiffView.swift b/RxCode/Views/Inspector/ThisThreadDiffView.swift index efaa59d4..4acea32b 100644 --- a/RxCode/Views/Inspector/ThisThreadDiffView.swift +++ b/RxCode/Views/Inspector/ThisThreadDiffView.swift @@ -1,6 +1,7 @@ import AppKit import SwiftUI import RxCodeCore +import RxCodeChatKit // MARK: - This Thread @@ -37,15 +38,26 @@ struct ThisThreadFileRow: View { let summary: FileEditSummary @Environment(WindowState.self) private var windowState @State private var isHovering = false + @State private var snapshotStat: (added: Int, removed: Int)? private var additions: Int { - summary.hunks.reduce(0) { count, hunk in + // Prefer the snapshot-pair count when it actually found differences. + // When the snapshot collapsed to zero (e.g. legacy rows, or any race + // where original ended up equal to modified) fall back to hunk lines + // so a real edit still shows activity in the sidebar. + if let stat = snapshotStat, stat.added > 0 || stat.removed > 0 { + return stat.added + } + return summary.hunks.reduce(0) { count, hunk in count + nonEmptyLineCount(hunk.newString) } } private var deletions: Int { - summary.hunks.reduce(0) { count, hunk in + if let stat = snapshotStat, stat.added > 0 || stat.removed > 0 { + return stat.removed + } + return summary.hunks.reduce(0) { count, hunk in count + nonEmptyLineCount(hunk.oldString) } } @@ -62,7 +74,8 @@ struct ThisThreadFileRow: View { name: summary.name, editHunks: summary.hunks, showFullFileDiff: true, - originalContent: summary.originalContent + originalContent: summary.originalContent, + modifiedContent: summary.modifiedContent ) } label: { HStack(spacing: 8) { @@ -112,12 +125,27 @@ struct ThisThreadFileRow: View { } .buttonStyle(.plain) .onHover { isHovering = $0 } + .task(id: summary.modifiedContent) { + await computeSnapshotStat() + } } private func nonEmptyLineCount(_ s: String) -> Int { guard !s.isEmpty else { return 0 } return s.components(separatedBy: "\n").count } + + private func computeSnapshotStat() async { + guard summary.modifiedContent != nil else { + snapshotStat = nil + return + } + let original = summary.originalContent ?? "" + let modified = summary.modifiedContent ?? "" + snapshotStat = await Task.detached(priority: .userInitiated) { + ChangeDiffView.snapshotStat(original: original, modified: modified) + }.value + } } struct BranchInfoView: View { diff --git a/RxCode/Views/MainView.swift b/RxCode/Views/MainView.swift index 41aa9da2..f7873bbc 100644 --- a/RxCode/Views/MainView.swift +++ b/RxCode/Views/MainView.swift @@ -280,7 +280,8 @@ struct MainView: View { editHunks: file.editHunks, gitDiffMode: file.gitDiffMode, showFullFileDiff: file.showFullFileDiff, - originalContent: file.originalContent + originalContent: file.originalContent, + modifiedContent: file.modifiedContent ) .frame(minWidth: 1000, idealWidth: 1400, maxWidth: 1920, minHeight: 600, idealHeight: 1000, maxHeight: 1200) diff --git a/RxCode/Views/ProjectWindowView.swift b/RxCode/Views/ProjectWindowView.swift index 559d1121..5bbb3b31 100644 --- a/RxCode/Views/ProjectWindowView.swift +++ b/RxCode/Views/ProjectWindowView.swift @@ -82,7 +82,8 @@ struct ProjectWindowView: View { editHunks: file.editHunks, gitDiffMode: file.gitDiffMode, showFullFileDiff: file.showFullFileDiff, - originalContent: file.originalContent + originalContent: file.originalContent, + modifiedContent: file.modifiedContent ) .frame(minWidth: 1000, idealWidth: 1400, maxWidth: 1920, minHeight: 600, idealHeight: 1000, maxHeight: 1200) diff --git a/RxCode/Views/Settings/MobileSettingsTab.swift b/RxCode/Views/Settings/MobileSettingsTab.swift index 191d12f7..aee12c0a 100644 --- a/RxCode/Views/Settings/MobileSettingsTab.swift +++ b/RxCode/Views/Settings/MobileSettingsTab.swift @@ -258,8 +258,11 @@ struct MobileSettingsTab: View { .font(.title2) .frame(width: 28) VStack(alignment: .leading, spacing: 2) { - Text(device.displayName) - .fontWeight(.medium) + HStack(spacing: 6) { + Text(device.displayName) + .fontWeight(.medium) + onlineStatePill(for: device) + } HStack(spacing: 6) { if let token = device.apnsToken, !token.isEmpty { Label("Push", systemImage: "bell.fill") @@ -311,6 +314,24 @@ struct MobileSettingsTab: View { .background(Color(nsColor: .controlBackgroundColor), in: RoundedRectangle(cornerRadius: 8)) } + @ViewBuilder + private func onlineStatePill(for device: PairedDevice) -> some View { + switch device.onlineState { + case .online: + Label("Online", systemImage: "circle.fill") + .font(.caption2) + .foregroundStyle(.green) + .labelStyle(.titleAndIcon) + case .offline: + Label("Offline", systemImage: "circle.fill") + .font(.caption2) + .foregroundStyle(.secondary) + .labelStyle(.titleAndIcon) + case .unknown: + EmptyView() + } + } + @ViewBuilder private func testNotificationButton(for device: PairedDevice) -> some View { if testNotificationDeviceID == device.id { diff --git a/RxCode/Views/Sidebar/GitStatusView.swift b/RxCode/Views/Sidebar/GitStatusView.swift index c216d1c2..e3f26d49 100644 --- a/RxCode/Views/Sidebar/GitStatusView.swift +++ b/RxCode/Views/Sidebar/GitStatusView.swift @@ -11,6 +11,7 @@ struct GitStatusView: View { @State private var localBranches: [String] = [] @State private var remoteBranches: [RemoteBranch] = [] @State private var headWatcher: (any DispatchSourceFileSystemObject)? + @State private var isInitializingGit = false var body: some View { VStack(alignment: .leading, spacing: 4) { @@ -34,6 +35,27 @@ struct GitStatusView: View { .font(.system(size: ClaudeTheme.size(12))) .foregroundStyle(ClaudeTheme.textTertiary) Spacer() + Button { + initializeGit() + } label: { + HStack(spacing: 4) { + if isInitializingGit { + ProgressView().controlSize(.mini) + } else { + Image(systemName: "plus.circle") + .font(.system(size: ClaudeTheme.size(10))) + } + Text(isInitializingGit ? "Initializing…" : "Initialize Git") + .font(.system(size: ClaudeTheme.size(11), weight: .medium)) + } + .foregroundStyle(ClaudeTheme.textPrimary) + .padding(.horizontal, 6) + .padding(.vertical, 3) + .background(ClaudeTheme.surfacePrimary.opacity(0.8), in: RoundedRectangle(cornerRadius: 4)) + } + .buttonStyle(.plain) + .disabled(isInitializingGit) + .help("Run git init in this project") } case .clean(let branch): @@ -274,6 +296,18 @@ struct GitStatusView: View { gitStatus = fresh } } + + private func initializeGit() { + guard !isInitializingGit else { return } + let path = projectPath + isInitializingGit = true + Task { + _ = await GitHelper.initRepository(at: path) + isInitializingGit = false + refresh() + loadBranches() + } + } } // MARK: - Git Status Model diff --git a/RxCodeMobile/Resources/Localizable.xcstrings b/RxCodeMobile/Resources/Localizable.xcstrings index d1d6eacc..498d20ed 100644 --- a/RxCodeMobile/Resources/Localizable.xcstrings +++ b/RxCodeMobile/Resources/Localizable.xcstrings @@ -14,23 +14,6 @@ } } }, - "%@ queued" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%@ queued" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ 条已排队" - } - } - } - }, "%@, Active" : { "localizations" : { "en" : { @@ -61,23 +44,6 @@ }, "%lld active jobs" : { - }, - "%lld plans ready to review" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%lld plans ready to review" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld 个计划可查看" - } - } - } }, "%lld queued" : { @@ -181,23 +147,6 @@ } } }, - "Accept Edits" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Accept Edits" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "接受编辑" - } - } - } - }, "Action" : { "localizations" : { "en" : { @@ -329,23 +278,6 @@ } } }, - "Add Header" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add Header" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加请求头" - } - } - } - }, "Add MCP Server" : { "localizations" : { "en" : { @@ -378,23 +310,6 @@ } } }, - "Add Variable" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add Variable" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "添加变量" - } - } - } - }, "Agent Clients" : { "localizations" : { "en" : { @@ -638,23 +553,6 @@ } } }, - "Ask" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Ask" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "询问" - } - } - } - }, "Assistant has a question" : { "localizations" : { "en" : { @@ -687,23 +585,6 @@ } } }, - "Auto" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Auto" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "自动" - } - } - } - }, "Auto-archive" : { "localizations" : { "en" : { @@ -930,23 +811,6 @@ }, "Browser Error" : { - }, - "Bypass" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Bypass" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "绕过" - } - } - } }, "Cancel" : { "localizations" : { @@ -1351,23 +1215,6 @@ } } }, - "Could not load changes." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Could not load changes." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无法加载变更。" - } - } - } - }, "Couldn't connect to the relay from the QR code. Check the relay address and try again." : { "localizations" : { "en" : { @@ -2017,23 +1864,6 @@ } } }, - "Environment Variables" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Environment Variables" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "环境变量" - } - } - } - }, "Extra High" : { "localizations" : { "en" : { @@ -2456,23 +2286,6 @@ } } }, - "Headers" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Headers" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "请求头" - } - } - } - }, "High" : { "localizations" : { "en" : { @@ -2510,6 +2323,12 @@ } } } + }, + "Initialize Git" : { + + }, + "Initializing…" : { + }, "Input" : { "localizations" : { @@ -3035,23 +2854,6 @@ } } }, - "Next" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Next" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "下一步" - } - } - } - }, "No agents found." : { "localizations" : { "en" : { @@ -3068,23 +2870,6 @@ } } }, - "No branch" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No branch" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无分支" - } - } - } - }, "No briefings for the current branch." : { "localizations" : { "en" : { @@ -3197,23 +2982,6 @@ } } }, - "No files have been edited in this thread yet." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No files have been edited in this thread yet." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "此对话尚未编辑任何文件。" - } - } - } - }, "No Folders" : { "localizations" : { "en" : { @@ -3401,23 +3169,6 @@ }, "No todos for this thread." : { - }, - "No uncommitted changes." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "No uncommitted changes." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有未提交变更。" - } - } - } }, "Normal" : { "localizations" : { @@ -3435,23 +3186,6 @@ } } }, - "Not connected to your Mac." : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Not connected to your Mac." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未连接到你的 Mac。" - } - } - } - }, "Nothing to Show" : { "localizations" : { "en" : { @@ -3582,23 +3316,6 @@ }, "Optional xcodebuild destination" : { - }, - "Other" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Other" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "其他" - } - } - } }, "Pair New Mac" : { "localizations" : { @@ -3712,23 +3429,6 @@ } } }, - "Plan" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划" - } - } - } - }, "Plan mode" : { "localizations" : { "en" : { @@ -3745,23 +3445,6 @@ } } }, - "Plan ready to review" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Plan ready to review" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "计划可查看" - } - } - } - }, "Privacy Report" : { }, @@ -4008,7 +3691,14 @@ } }, "Response in progress" : { - + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "响应进行中" + } + } + } }, "Response notifications" : { "localizations" : { @@ -4074,23 +3764,6 @@ } } }, - "Run Profile" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Run Profile" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "运行配置" - } - } - } - }, "Run Profile Error" : { "localizations" : { "en" : { @@ -4559,23 +4232,6 @@ }, "SSE" : { - }, - "Staged" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Staged" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已暂存" - } - } - } }, "Start a conversation from your Mac" : { "localizations" : { @@ -4660,23 +4316,6 @@ } } }, - "Submit" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Submit" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "提交" - } - } - } - }, "Summarization" : { "localizations" : { "en" : { @@ -4740,6 +4379,12 @@ } } } + }, + "Switch to horizontal scroll" : { + + }, + "Switch to wrap" : { + }, "Syncing settings…" : { "localizations" : { @@ -4856,23 +4501,6 @@ } } }, - "this Mac" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "this Mac" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "这台 Mac" - } - } - } - }, "This permanently deletes the thread and all of its messages. This cannot be undone." : { "localizations" : { "en" : { @@ -5205,40 +4833,6 @@ } } }, - "Unknown Mac" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Unknown Mac" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未知 Mac" - } - } - } - }, - "Unknown Project" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Unknown Project" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未知项目" - } - } - } - }, "Unrecognized pairing link. Generate a new QR code on your Mac." : { "localizations" : { "en" : { @@ -5271,57 +4865,6 @@ } } }, - "Unstaged" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Unstaged" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未暂存" - } - } - } - }, - "Untitled" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Untitled" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未命名" - } - } - } - }, - "Untracked" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Untracked" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未跟踪" - } - } - } - }, "Updated %@. Pull to refresh." : { "localizations" : { "en" : { diff --git a/RxCodeMobile/State/MobileAppState+Intents.swift b/RxCodeMobile/State/MobileAppState+Intents.swift index fdfdb268..da07db19 100644 --- a/RxCodeMobile/State/MobileAppState+Intents.swift +++ b/RxCodeMobile/State/MobileAppState+Intents.swift @@ -277,6 +277,19 @@ extension MobileAppState { try? await client.send(.branchOpRequest(request), toHex: pairedDesktopPubkey) } + /// Tell the desktop to run `git init` at the project's root. The eventual + /// snapshot broadcast carries the freshly-initialized branch. + func initProjectGit(projectID: UUID) async { + guard isPaired else { return } + let request = BranchOpRequestPayload( + projectID: projectID, + operation: .initGit, + branch: "" + ) + inFlightBranchOps.insert(request.clientRequestID) + try? await client.send(.branchOpRequest(request), toHex: pairedDesktopPubkey) + } + func clearBranchOpError() { lastBranchOpError = nil } diff --git a/RxCodeMobile/Views/MobileBriefingDetailView.swift b/RxCodeMobile/Views/MobileBriefingDetailView.swift index ec529b2e..f1bdaba1 100644 --- a/RxCodeMobile/Views/MobileBriefingDetailView.swift +++ b/RxCodeMobile/Views/MobileBriefingDetailView.swift @@ -7,6 +7,10 @@ struct MobileBriefingDetailView: View { @EnvironmentObject private var state: MobileAppState @Namespace private var glassNamespace let groupKey: BriefingGroupKey + var onOpenSession: (String) -> Void = { _ in } + + @State private var showingNewThread = false + @State private var isInitializingGit = false var body: some View { ScrollView { @@ -23,6 +27,27 @@ struct MobileBriefingDetailView: View { .accessibilityIdentifier("briefing-detail-screen") .navigationTitle(projectName) .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button { + showingNewThread = true + } label: { + Image(systemName: "square.and.pencil") + .font(.system(size: 16, weight: .medium)) + } + .accessibilityLabel("New Thread") + .accessibilityIdentifier("briefing-detail-new-thread") + } + } + .sheet(isPresented: $showingNewThread) { + NewThreadSheet( + projectID: groupKey.projectId, + preferredBranch: groupKey.branch + ) { newSessionID in + onOpenSession(newSessionID) + } + .environmentObject(state) + } .refreshable { await state.refreshSnapshot() } @@ -43,6 +68,20 @@ struct MobileBriefingDetailView: View { state.projects.first(where: { $0.id == groupKey.projectId })?.name ?? "Unknown Project" } + private var isUnknownBranch: Bool { + groupKey.branch.lowercased() == "unknown" + } + + private func initializeGit() { + guard !isInitializingGit else { return } + isInitializingGit = true + Task { + await state.initProjectGit(projectID: groupKey.projectId) + await state.refreshSnapshot() + isInitializingGit = false + } + } + // MARK: - Header Card private var headerCard: some View { @@ -64,18 +103,42 @@ struct MobileBriefingDetailView: View { .foregroundStyle(.primary) HStack(spacing: 12) { - // Branch chip - HStack(spacing: 5) { - Image(systemName: "arrow.triangle.branch") - .font(.system(size: 10, weight: .medium)) - Text(groupKey.branch) - .font(.caption.weight(.medium)) + // Branch chip — falls back to an Init Git action when the + // desktop hasn't initialized a repo (branch is "unknown"). + if isUnknownBranch { + Button { + initializeGit() + } label: { + HStack(spacing: 5) { + if isInitializingGit { + ProgressView().controlSize(.mini) + } else { + Image(systemName: "plus.circle") + .font(.system(size: 10, weight: .medium)) + } + Text(isInitializingGit ? "Initializing…" : "Initialize Git") + .font(.caption.weight(.medium)) + } + .foregroundStyle(.secondary) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(.ultraThinMaterial, in: Capsule()) + } + .buttonStyle(.plain) + .disabled(isInitializingGit) + } else { + HStack(spacing: 5) { + Image(systemName: "arrow.triangle.branch") + .font(.system(size: 10, weight: .medium)) + Text(groupKey.branch) + .font(.caption.weight(.medium)) + } + .foregroundStyle(.secondary) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(.ultraThinMaterial, in: Capsule()) } - .foregroundStyle(.secondary) - .padding(.horizontal, 8) - .padding(.vertical, 4) - .background(.ultraThinMaterial, in: Capsule()) - + // Updated time if let updatedAt = group?.updatedAt { Text(updatedAt.formatted(.relative(presentation: .named))) diff --git a/RxCodeMobile/Views/MobileBriefingView.swift b/RxCodeMobile/Views/MobileBriefingView.swift index 224245ba..80032c17 100644 --- a/RxCodeMobile/Views/MobileBriefingView.swift +++ b/RxCodeMobile/Views/MobileBriefingView.swift @@ -27,6 +27,7 @@ struct MobileBriefingView: View { @EnvironmentObject private var state: MobileAppState @Namespace private var glassNamespace var onCloseChat: () -> Void = {} + var onOpenSession: (String) -> Void = { _ in } /// Selected project ids for filtering. Empty = show every project. @State private var selectedProjectIds: Set = [] @@ -83,7 +84,7 @@ struct MobileBriefingView: View { await state.refreshSnapshot() } .navigationDestination(for: BriefingGroupKey.self) { key in - MobileBriefingDetailView(groupKey: key) + MobileBriefingDetailView(groupKey: key, onOpenSession: onOpenSession) } .navigationDestination(for: String.self) { sessionID in MobileChatView(sessionID: sessionID, onClose: onCloseChat) @@ -498,9 +499,9 @@ private struct BriefingListCard: View { .lineLimit(1) HStack(spacing: 6) { - Image(systemName: "arrow.triangle.branch") + Image(systemName: group.branch.lowercased() == "unknown" ? "plus.circle" : "arrow.triangle.branch") .font(.system(size: 9, weight: .medium)) - Text(group.branch) + Text(group.branch.lowercased() == "unknown" ? "Initialize Git" : group.branch) .font(.system(size: 12)) .lineLimit(1) } @@ -673,9 +674,9 @@ private struct BriefingCard: View { .lineLimit(1) HStack(spacing: 6) { - Image(systemName: "arrow.triangle.branch") + Image(systemName: group.branch.lowercased() == "unknown" ? "plus.circle" : "arrow.triangle.branch") .font(.system(size: 10, weight: .medium)) - Text(group.branch) + Text(group.branch.lowercased() == "unknown" ? "Initialize Git" : group.branch) .font(.caption) .lineLimit(1) } diff --git a/RxCodeMobile/Views/NewThreadSheet.swift b/RxCodeMobile/Views/NewThreadSheet.swift index e04a5d64..389738f9 100644 --- a/RxCodeMobile/Views/NewThreadSheet.swift +++ b/RxCodeMobile/Views/NewThreadSheet.swift @@ -13,6 +13,7 @@ struct NewThreadSheet: View { @Environment(\.dismiss) private var dismiss let projectID: UUID + var preferredBranch: String? = nil let onSessionCreated: (String) -> Void @State private var text: String = "" @@ -49,6 +50,7 @@ struct NewThreadSheet: View { composer NewThreadConfigStrip( projectID: projectID, + preferredBranch: preferredBranch, selectedProvider: $selectedProvider, selectedModelID: $selectedModelID, selectedPermissionMode: $selectedPermissionMode, @@ -240,11 +242,13 @@ struct NewThreadSheet: View { struct NewThreadConfigStrip: View { @EnvironmentObject private var state: MobileAppState let projectID: UUID + var preferredBranch: String? = nil @Binding var selectedProvider: AgentProvider? @Binding var selectedModelID: String? @Binding var selectedPermissionMode: PermissionMode @Binding var planModeEnabled: Bool @State private var showingCreateBranch = false + @State private var didApplyPreferredBranch = false private let columns = [ GridItem(.flexible(), spacing: 12), @@ -277,6 +281,10 @@ struct NewThreadConfigStrip: View { ) .environmentObject(state) } + .onAppear(perform: applyPreferredBranchIfNeeded) + .onChange(of: state.projectBranches[projectID]) { _, _ in + applyPreferredBranchIfNeeded() + } .alert( "Branch operation failed", isPresented: branchOpErrorBinding, @@ -303,7 +311,22 @@ struct NewThreadConfigStrip: View { } private var currentBranch: String? { - state.projectBranches[projectID] + state.projectBranches[projectID] ?? preferredBranch + } + + /// When the sheet was opened from a context that knows the desired branch + /// (e.g. the briefing detail screen), ask the desktop to switch to it so + /// the new thread spawns on the right branch. Only fires once per sheet + /// presentation, and only when the desktop is on a different branch. + private func applyPreferredBranchIfNeeded() { + guard !didApplyPreferredBranch, let target = preferredBranch else { return } + let actual = state.projectBranches[projectID] + guard actual != nil, actual != target else { + if actual == target { didApplyPreferredBranch = true } + return + } + didApplyPreferredBranch = true + Task { await state.switchProjectBranch(projectID: projectID, branch: target) } } private var branchMenu: some View { diff --git a/RxCodeMobile/Views/RootView.swift b/RxCodeMobile/Views/RootView.swift index c3daa1d2..5aaf0209 100644 --- a/RxCodeMobile/Views/RootView.swift +++ b/RxCodeMobile/Views/RootView.swift @@ -186,7 +186,10 @@ struct RootView: View { private var phoneTabs: some View { TabView(selection: $selectedTab) { NavigationStack(path: $briefingDetailPath) { - MobileBriefingView(onCloseChat: { closeBriefingChat() }) + MobileBriefingView( + onCloseChat: { closeBriefingChat() }, + onOpenSession: { briefingDetailPath.append($0) } + ) } .tabItem { Label("Briefing", systemImage: "doc.text") @@ -258,7 +261,10 @@ struct RootView: View { NavigationStack(path: $briefingDetailPath) { Group { if let groupKey = selectedBriefingGroup { - MobileBriefingDetailView(groupKey: groupKey) + MobileBriefingDetailView( + groupKey: groupKey, + onOpenSession: { briefingDetailPath.append($0) } + ) } else { ContentUnavailableView { Label("No Selection", systemImage: "doc.text") @@ -350,11 +356,18 @@ struct RootView: View { } private var isViewingBriefingDetail: Bool { - guard !briefingDetailPath.isEmpty else { return false } if compactClass == .compact { - return selectedTab == .briefing + // iPhone: the path holds [briefingGroupKey, …], so a non-empty + // path while on the Briefing tab means a detail screen is open. + return selectedTab == .briefing && !briefingDetailPath.isEmpty } + // iPad: the selected group lives in `selectedBriefingGroup`, not on + // the path — so the path is empty while sitting on briefing detail + // and only grows when a thread is pushed. Either signal means the + // user is inside the briefing flow and a desktop-driven session + // change must not yank them into the projects column. return showingBriefing + && (selectedBriefingGroup != nil || !briefingDetailPath.isEmpty) } /// Consume a pending APNs deep link (set by a notification tap) and navigate diff --git a/RxCodeMobile/Views/ThreadChangesSheet.swift b/RxCodeMobile/Views/ThreadChangesSheet.swift index 34238a0a..74746c57 100644 --- a/RxCodeMobile/Views/ThreadChangesSheet.swift +++ b/RxCodeMobile/Views/ThreadChangesSheet.swift @@ -138,7 +138,7 @@ struct ThreadChangesSheet: View { path: edit.path, badge: edit.containsWrite ? "W" : "M", badgeColor: edit.containsWrite ? .blue : .orange, - stat: hunkStat(edit.hunks) + stat: turnStat(edit) ) } } @@ -148,6 +148,20 @@ struct ThreadChangesSheet: View { } private func turnDiff(_ edit: SyncFileEdit) -> ThreadChangeDetailView.Diff { + // Prefer the snapshot pair, but only when it actually yields a diff — + // if `original == modified` (e.g. the original snapshot lost its + // capture race on a large file) fall through so the user still sees + // the change as full-file diff or hunks. + if let modified = edit.modifiedContent, + let original = edit.originalContent, + original != modified { + return .snapshot(original: original, modified: modified) + } + if let modified = edit.modifiedContent, + edit.originalContent == nil, + !modified.isEmpty { + return .snapshot(original: "", modified: modified) + } if let fullFileDiff = edit.fullFileDiff, !fullFileDiff.isEmpty { return .unified(fullFileDiff) } @@ -156,6 +170,20 @@ struct ThreadChangesSheet: View { }) } + /// Sidebar `+/-` count. Prefers a fresh snapshot-pair diff when both + /// snapshots are present so the row's numbers match what the detail page + /// renders; falls back to hunk-newline counting for legacy edits or when + /// the snapshot pair collapsed to zero (race-loss on the original capture). + private func turnStat(_ edit: SyncFileEdit) -> (added: Int, removed: Int) { + if let modified = edit.modifiedContent { + let stat = ChangeDiffView.snapshotStat(original: edit.originalContent ?? "", modified: modified) + if stat.added > 0 || stat.removed > 0 { + return stat + } + } + return hunkStat(edit.hunks) + } + // MARK: - Uncommitted @ViewBuilder @@ -291,6 +319,7 @@ struct ThreadChangeDetailView: View { enum Diff { case unified(String) case hunks([PreviewFile.EditHunk]) + case snapshot(original: String, modified: String) } let title: String @@ -298,48 +327,70 @@ struct ThreadChangeDetailView: View { let diff: Diff let truncated: Bool - var body: some View { - ScrollView { - VStack(alignment: .leading, spacing: 8) { - Text(subtitle) - .font(.caption2) - .foregroundStyle(.secondary) - .textSelection(.enabled) - .padding(.horizontal, 8) - - if truncated { - Label( - "Diff truncated — open this file on your Mac for the full diff.", - systemImage: "scissors" - ) - .font(.caption) - .foregroundStyle(.secondary) - .padding(.horizontal, 8) - } + @State private var diffDisplay: DiffView.LineDisplay = .wrap - diffBody + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text(subtitle) + .font(.caption2) + .foregroundStyle(.secondary) + .textSelection(.enabled) + .padding(.horizontal, 8) + .padding(.top, 8) + + if truncated { + Label( + "Diff truncated — open this file on your Mac for the full diff.", + systemImage: "scissors" + ) + .font(.caption) + .foregroundStyle(.secondary) + .padding(.horizontal, 8) } - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.vertical, 8) + + diffBody + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) } + .frame(maxWidth: .infinity, alignment: .leading) .navigationTitle(title) .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button { + diffDisplay = (diffDisplay == .wrap) ? .scroll : .wrap + } label: { + Image(systemName: diffDisplay == .wrap + ? "arrow.left.and.right" + : "text.alignleft") + } + .accessibilityLabel(diffDisplay == .wrap + ? "Switch to horizontal scroll" + : "Switch to wrap") + } + } } @ViewBuilder private var diffBody: some View { + let language = SyntaxHighlighter.language(forFilename: title) switch diff { case .unified(let text): if text.isEmpty { emptyDiff } else { - ChangeDiffView(unifiedDiff: text) + ChangeDiffView(unifiedDiff: text, display: diffDisplay, language: language) } case .hunks(let hunks): if hunks.isEmpty { emptyDiff } else { - ChangeDiffView(hunks: hunks) + ChangeDiffView(hunks: hunks, display: diffDisplay, language: language) + } + case .snapshot(let original, let modified): + if original == modified { + emptyDiff + } else { + ChangeDiffView(original: original, modified: modified, display: diffDisplay, language: language) } } } diff --git a/RxCodeMobileUITests/Mock/MockRelayServer.swift b/RxCodeMobileUITests/Mock/MockRelayServer.swift index 32ecf9f3..67a44ab9 100644 --- a/RxCodeMobileUITests/Mock/MockRelayServer.swift +++ b/RxCodeMobileUITests/Mock/MockRelayServer.swift @@ -32,7 +32,7 @@ nonisolated final class MockRelayServer: @unchecked Sendable { let desktopIdentity: DeviceIdentity var desktopPublicKeyHex: String { desktopIdentity.publicKeyHex } - private let fixtures: MockFixtures + private let baseFixtures: MockFixtures private let queue = DispatchQueue(label: "com.idealapp.RxCodeMobile.MockRelayServer") private var listener: NWListener? @@ -40,6 +40,18 @@ nonisolated final class MockRelayServer: @unchecked Sendable { /// Learned from the first decrypted envelope's `from` field. private var mobilePublicKey: Curve25519.KeyAgreement.PublicKey? + // MARK: - Dynamic state + // + // Sessions/threads that the test created at runtime by sending a + // `newSessionRequest`. The mock server treats those exactly like persisted + // fixture rows — they ride along in every snapshot from then on so the + // mobile app sees a stable thread on subsequent refreshes/subscribes, + // letting tests assert the chat view stays populated after creation. + private var dynamicSessions: [SessionSummary] = [] + private var dynamicThreadSummaries: [MobileThreadSummary] = [] + private var dynamicMessagesBySession: [String: [ChatMessage]] = [:] + private var newSessionCounter = 0 + /// Ephemeral port the listener bound to. Valid after `start()` returns. private(set) var port: UInt16 = 0 @@ -47,7 +59,7 @@ nonisolated final class MockRelayServer: @unchecked Sendable { var relayURL: String { "ws://127.0.0.1:\(port)/ws" } init(fixtures: MockFixtures) { - self.fixtures = fixtures + self.baseFixtures = fixtures // Fixed 32 bytes — guaranteed a valid private key, so `try!` is safe. let key = try! Curve25519.KeyAgreement.PrivateKey( rawRepresentation: Data(Self.desktopPrivateKeyBytes) @@ -161,10 +173,10 @@ nonisolated final class MockRelayServer: @unchecked Sendable { switch payload { case .requestSnapshot(let request): - send(.snapshot(fixtures.snapshot(activeSessionID: request.activeSessionID)), + send(.snapshot(currentSnapshot(activeSessionID: request.activeSessionID)), on: connection) case .subscribeSession(let request): - send(.snapshot(fixtures.snapshot(activeSessionID: request.sessionID)), + send(.snapshot(currentSnapshot(activeSessionID: request.sessionID)), on: connection) case .loadMoreMessages(let request): // The fixture window is the whole thread, so there is nothing older. @@ -174,12 +186,95 @@ nonisolated final class MockRelayServer: @unchecked Sendable { messages: [], hasMore: false )), on: connection) + case .newSessionRequest(let request): + let sessionID = registerNewSession(for: request) + send(.snapshot(currentSnapshot(activeSessionID: sessionID)), on: connection) default: // pairRequest, apnsToken, userMessage, ping, … — decrypt and ignore. break } } + // MARK: - Snapshot assembly + + /// Builds a `snapshot` payload reflecting the current base fixtures plus + /// any sessions that were created at runtime via `newSessionRequest`. + private func currentSnapshot(activeSessionID: String?) -> SnapshotPayload { + let sessions = baseFixtures.sessions + dynamicSessions + let threadSummaries = baseFixtures.threadSummaries + dynamicThreadSummaries + let messages = activeSessionID.flatMap { id in + dynamicMessagesBySession[id] ?? baseFixtures.messagesBySession[id] + } + return SnapshotPayload( + projects: baseFixtures.projects, + sessions: sessions, + branchBriefings: baseFixtures.branchBriefings, + threadSummaries: threadSummaries, + settings: nil, + activeSessionID: activeSessionID, + activeSessionMessages: messages, + activeSessionHasMore: false, + projectBranches: nil, + usage: nil, + hostMetrics: nil, + runProfiles: nil, + runTasks: nil, + webProxy: nil + ) + } + + /// Materializes a fresh session + thread summary + canned transcript for a + /// `newSessionRequest`, mirroring what the desktop would persist before + /// pushing a snapshot back. Returns the new session ID so the snapshot + /// reply can mark it as active. + private func registerNewSession(for request: NewSessionRequestPayload) -> String { + newSessionCounter += 1 + let sessionID = "sess-new-\(newSessionCounter)" + let now = Date(timeIntervalSince1970: 1_716_000_000) + let title = request.initialText? + .trimmingCharacters(in: .whitespacesAndNewlines) + .prefix(60) + .description ?? "New Thread" + // The briefing detail's branch is plumbed through `preferredBranch`, but + // the mock doesn't actually receive it on the wire — fall back to the + // first briefing's branch for that project so the new thread lands in + // the same briefing group the test is asserting against. + let branch = baseFixtures.branchBriefings + .first(where: { $0.projectId == request.projectID })?.branch ?? "main" + + let session = SessionSummary( + id: sessionID, + projectId: request.projectID, + title: title, + updatedAt: now, + isPinned: false, + isArchived: false + ) + let summary = MobileThreadSummary( + sessionId: sessionID, + projectId: request.projectID, + branch: branch, + title: title, + summary: "", + updatedAt: now + ) + var transcript: [ChatMessage] = [] + if let text = request.initialText, !text.isEmpty { + transcript.append(ChatMessage(role: .user, content: text, timestamp: now)) + } + transcript.append(ChatMessage( + role: .assistant, + content: "Assistant reply inside \(title).", + isResponseComplete: true, + timestamp: now + )) + + dynamicSessions.append(session) + dynamicThreadSummaries.append(summary) + dynamicMessagesBySession[sessionID] = transcript + return sessionID + } + /// Seal `payload` for the mobile peer and send it as a binary WS message. private func send(_ payload: Payload, on connection: NWConnection) { guard let mobileKey = mobilePublicKey, diff --git a/RxCodeMobileUITests/Support/MobileAppRobot.swift b/RxCodeMobileUITests/Support/MobileAppRobot.swift index f6c2cc9a..82bda2a1 100644 --- a/RxCodeMobileUITests/Support/MobileAppRobot.swift +++ b/RxCodeMobileUITests/Support/MobileAppRobot.swift @@ -26,6 +26,14 @@ struct MobileAppRobot { var briefingListScreen: XCUIElement { element(id: "briefing-list-screen") } var briefingDetailScreen: XCUIElement { element(id: "briefing-detail-screen") } var anyBriefingThreadRow: XCUIElement { firstButton(prefix: "briefing-thread-row-") } + var briefingDetailNewThreadButton: XCUIElement { element(id: "briefing-detail-new-thread") } + + // MARK: - New Thread sheet + + var newThreadInput: XCUIElement { + app.descendants(matching: .any).matching(identifier: "new-thread-input").firstMatch + } + var newThreadSendButton: XCUIElement { element(id: "new-thread-send") } // MARK: - Projects / threads @@ -147,6 +155,26 @@ struct MobileAppRobot { ) } + /// Types `text` into the New Thread sheet's prompt input and taps Send. + /// Waits for the sheet to dismiss so the caller can immediately assert on + /// whatever surface comes next. + func createNewThread( + with text: String, + file: StaticString = #filePath, + line: UInt = #line + ) { + let input = newThreadInput + XCTAssertTrue( + input.waitForExistence(timeout: timeout), + "New Thread input never appeared", + file: file, line: line + ) + // `TextField` requires focus before typeText. Tap the input to focus it. + tapWhenReady(input) + input.typeText(text) + tap(newThreadSendButton, "New Thread send button", file: file, line: line) + } + /// Asserts the chat screen is shown with at least one message rendered. func assertMessagesShown(file: StaticString = #filePath, line: UInt = #line) { XCTAssertTrue( diff --git a/RxCodeMobileUITests/iPadNavigationUITests.swift b/RxCodeMobileUITests/iPadNavigationUITests.swift index 3e759a66..4e660a6b 100644 --- a/RxCodeMobileUITests/iPadNavigationUITests.swift +++ b/RxCodeMobileUITests/iPadNavigationUITests.swift @@ -26,6 +26,31 @@ final class iPadNavigationUITests: XCTestCase { r.assertExists(r.briefingListScreen, "briefing list column still visible") } + /// Briefing split → briefing detail → New Thread → compose → send → chat + /// for the new thread is shown in the detail column, the briefing list + /// column stays visible, and the chat keeps its content after the desktop + /// snapshot settles (the empty-chat-after-creation regression). + @MainActor + func testNewThreadFromBriefingSplitOpensChat() throws { + let r = try UITestRunner.launch(.pad, on: self).robot + + r.tap(r.anyBriefingListCard, "a briefing card in the list column") + r.assertExists(r.briefingDetailScreen, "briefing detail screen") + + r.tap(r.briefingDetailNewThreadButton, "new thread button in briefing detail") + r.createNewThread(with: "Help me investigate the empty chat bug.") + + // The chat appears in the detail column and the briefing list column + // stays alongside it — the split view never lost the briefing context. + r.assertMessagesShown() + r.assertExists(r.briefingListScreen, "briefing list column still visible") + // Sustain the chat for a beat so a delayed snapshot can't quietly + // navigate us into the projects split. + Thread.sleep(forTimeInterval: 2.0) + r.assertExists(r.chatScreen, "chat screen remains after snapshot settles") + r.assertExists(r.briefingListScreen, "briefing list column still visible after settle") + } + /// Case 4: Projects → project → thread list → thread → messages, and the /// thread list column remains visible (split view keeps context). @MainActor diff --git a/RxCodeMobileUITests/iPhoneNavigationUITests.swift b/RxCodeMobileUITests/iPhoneNavigationUITests.swift index f4dd2e49..d8dffa0b 100644 --- a/RxCodeMobileUITests/iPhoneNavigationUITests.swift +++ b/RxCodeMobileUITests/iPhoneNavigationUITests.swift @@ -24,6 +24,29 @@ final class iPhoneNavigationUITests: XCTestCase { r.assertDisappears(r.chatScreen, "chat screen after navigating back") } + /// Briefing tab → briefing detail → New Thread → compose → send → chat for + /// the new thread is shown and remains shown after the desktop snapshot + /// settles (the empty-chat-after-creation regression). + @MainActor + func testNewThreadFromBriefingDetailOpensChat() throws { + let r = try UITestRunner.launch(.phone, on: self).robot + + r.tap(r.briefingTab, "Briefing tab") + r.tap(r.anyBriefingCard, "a briefing card") + r.assertExists(r.briefingDetailScreen, "briefing detail screen") + + r.tap(r.briefingDetailNewThreadButton, "new thread button in briefing detail") + r.createNewThread(with: "Help me investigate the empty chat bug.") + + // The chat screen for the freshly-created thread must appear and + // remain populated — i.e. the briefing navigation stack should hold + // it, not get reset by the snapshot-driven `activeSessionID` change. + r.assertMessagesShown() + // Sustain the assertion a bit so a delayed snapshot can't pop us off. + Thread.sleep(forTimeInterval: 2.0) + r.assertExists(r.chatScreen, "chat screen remains after snapshot settles") + } + /// Case 3: Projects tab → project → thread list → thread → messages → back → /// thread list is shown again. @MainActor