mirror of
https://github.com/wu736139669/hapi.git
synced 2026-11-07 01:21:37 +00:00
The hub's fork, rewind and export routes had no iOS UI. The chat's menu now offers: - Fork Conversation: when the agent advertises forkCurrent, the session is live and no Codex turn is running (the web gate). The new session opens in place of this chat. - Rewind or Fork…: a sheet listing loaded user messages that have a native point in metadata.conversationHistoryPoints. Each row offers a confirmed Fork from Here or Rewind to Here, gated like web: forks need an idle turn except on Codex, and rewinds always need one. The actions live in a sheet, not on the transcript bubbles, because those keep text selection and cached row heights. After a rewind the tail resyncs with a history reset. An ambiguous native boundary (409 ambiguous_native_boundary_fork_safe) offers a fork from the same point instead. - Export Conversation…: saves the hub's lossless JSON payload through the Files save panel, using the web download's filename. A large export asks before retrying with force; a 413 explains the limit. Markdown export stays web-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
3.2 KiB
Swift
73 lines
3.2 KiB
Swift
import Foundation
|
|
|
|
/// Display-point localization for user-facing strings emitted by HapiKit
|
|
/// (the package layer stays language-free, A-M5): a known package-produced
|
|
/// notice maps to its `Localizable.xcstrings` entry, everything else
|
|
/// (server-originated errors, dynamic content) passes through verbatim.
|
|
///
|
|
/// Covered sources: `ChatInteractor` notices, `DictationController` errors,
|
|
/// `MessageWindowController` tail-sync warnings, and the files models'
|
|
/// fallback errors. Low-value/debug package strings are deliberately not
|
|
/// mapped.
|
|
enum LocalizedNoticeMapper {
|
|
static func map(_ message: String) -> String {
|
|
guard knownMessages.contains(message) else { return message }
|
|
return String(localized: String.LocalizationValue(message))
|
|
}
|
|
|
|
/// Exact strings the package can emit — each is a key in
|
|
/// `Localizable.xcstrings` (hand-authored; runtime-built keys are not
|
|
/// extracted by the compiler).
|
|
private static let knownMessages: Set<String> = [
|
|
// ChatInteractor
|
|
"Attachments are still uploading — wait, or retry/remove the failed ones",
|
|
"Failed to abort",
|
|
"Session is inactive and could not be resumed",
|
|
"Failed to cancel queued message",
|
|
"Message cancelled — kept your current draft",
|
|
"Already delivered to the agent",
|
|
"Failed to steer message",
|
|
"Request was already handled",
|
|
"Request failed",
|
|
"Failed to load models",
|
|
"Failed to update session",
|
|
"Failed to rename session",
|
|
"Failed to delete session",
|
|
"Active sessions can't be deleted — archive first",
|
|
"Failed to reopen session",
|
|
"Scheduled messages can't include attachments — remove them or send now",
|
|
"Scheduled time must be in the future",
|
|
"Scheduled sends can be at most 7 days ahead",
|
|
"Failed to fork conversation",
|
|
"Failed to rewind conversation",
|
|
"Draft parked to scratchlist",
|
|
"Scratchlist is full (200 entries)",
|
|
"Couldn't park the draft — check the hub connection",
|
|
"Drafts can contain at most 10,000 characters — shorten the text before saving",
|
|
"Couldn't prepare the attachments — retry or remove the failed files",
|
|
"The attachments exceed the scratchlist limits — remove a file or choose a smaller one",
|
|
"Your input changed — review it and try again",
|
|
"Couldn't queue the draft — retry",
|
|
"Draft added to the send queue",
|
|
"Already queued — couldn't remove the draft. Retry removal only.",
|
|
// DictationController
|
|
"Could not start recording",
|
|
"Could not reach the hub",
|
|
"Audio recording failed",
|
|
"No audio was recorded",
|
|
"Transcription failed",
|
|
// NewSessionLogic
|
|
"Name needs at least one letter or digit",
|
|
"Path is outside workspace roots",
|
|
// MessageWindowController (degraded-sync banner)
|
|
"Failed to synchronize messages",
|
|
"Failed to load older messages",
|
|
// FilesModel / FileViewerModel fallbacks
|
|
"Git status unavailable",
|
|
"Failed to list directory",
|
|
"Failed to search files",
|
|
"Failed to read file",
|
|
"Failed to load diff",
|
|
]
|
|
}
|