mirror of
https://github.com/wu736139669/hapi.git
synced 2026-11-08 01:43:07 +00:00
* feat(android): render chat markdown math with offline KaTeX Port the web math pipeline to Android chat markdown. A new MarkdownMath pre-pass in :core:protocol extracts math with web semantics (remark-math singleDollarTextMath:false + remark-latex- bracket-math): $$ display flows, $$ text math only when the closer run equals the opener and stays inside the paragraph, single $ never triggers math (currency stays prose), \(..\)/\[..\] bracket pairs, backslash-escaped delimiters stay literal, and code spans, fences, links and link reference definitions are fully protected. Matches are lifted behind private-use placeholder tokens and re-inserted as MathInlineNode/MathBlockNode custom nodes, hoisting display math out of paragraphs while blockquote/list containers survive the reparse. 37 JVM tests mirror the web suite's cases. Rendering is a shared offline WebView (ui/markdown/MathWebView.kt) fed a self-built HTML document (MathDocument.kt) against bundled assets/katex/ (KaTeX 0.16.45, same version as web). The view is network-blocked (blockNetworkLoads + shouldInterceptRequest refuses http/https/ws/wss) with file/content access disabled; asset URLs still resolve through the file:///android_asset/katex/ base URL. Theme color and font size are injected per render and the document reports its height through a JS bridge (ResizeObserver + onPageFinished re-measure). KaTeX failures follow the web's three-tier semantics, degrading to monospace raw TeX. Inline \(..\) and single-paragraph $$ math degrades to monospace TeX for v1: AnnotatedString cannot host a WebView and one WebView per fragment is too costly in chat lists. The parser still emits MathInlineNode so a future renderer can upgrade inline rendering without touching the extraction layer. Co-Authored-By: Claude Code <noreply@anthropic.com> via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(android): convert CSS pixels correctly at the math WebView boundary The JS bridge reports scrollHeight in CSS pixels, but KaTeXMathBlock treated the value as Android physical pixels and divided it by the screen density when sizing the modifier: on a density-3 device a reported 90 CSS px block collapsed to 30dp instead of ~90dp. The font conversion had the opposite mismatch — 16sp chat text went through TextUnit.toPx() (physical pixels) and was injected as `font-size: 48px` CSS, making formulas render ~3x too large on the same screen. Define the two boundary conversions explicitly as pure functions next to the document builder and unit-test them: - spFontToCssPx: CSS px and sp are both density-independent, so only the user's font-scale preference crosses the boundary; density never enters (16sp stays 16 CSS px at any density, 21 at fontScale 1.3). - cssPxToDp: reported CSS px map 1:1 to dp at the default WebView scale, multiplied by WebView.scale when the view is zoomed. The document now also pins the viewport with `width=device-width, initial-scale=1`, making the 1 CSS px = 1 dp default scale an explicit property of the document rather than a WebView default, with a regression test asserting the meta tag. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(android): refresh the math WebView height callback across spec changes KaTeXMathBlock keyed its height state with remember(spec) but assigned MathWebView.onHeightChanged inside AndroidView.factory, which runs only when the Android view is created. The callback therefore captured the initial spec's state object: when LaTeX, theme color or font size changed, remember(spec) minted a new state while AndroidView retained the existing view and its stale callback, so every measurement from the reloaded document updated the orphaned state and the current block stayed at its 22dp minimum. Keep one stable holder (MathViewHeightState) remembered unkeyed for the mounted view, reset it explicitly in onRender when the spec changes, and re-point the view's callback plus reset the height inside AndroidView.update before rendering — the creation-time callback then always feeds live state. JVM tests drive the holder through spec changes on one mounted view (the pre-fix wiring cannot compile against this shape: the factory-captured remember(spec) state is exactly the orphan the holder removes). Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(protocol): bound dollar flow math closing to the enclosing container findFlowClose kept scanning after the opening line left its container and accepted an unprefixed closing run, so `> $$\n> x\n\nOrdinary prose\n\n$$\ny\n$$` paired the quoted opener with the later top-level `$$`: the prose was swallowed into the formula and the final `$$` lost its own opener. remark-math (verified against micromark-extension-math, whose math flow is `concrete` and dies with its container) renders the quote's math, the prose and a separate top-level equation instead. Bound matching to the opening container, distinguishing container shapes: a closer is only accepted from a line that still carries the container prefix; a blank line ends a blockquote (a following `> $$` opens a NEW quote, while a `>`-only line is an in-quote blank the container survives); a list item may resume after blank lines (loose lists), so blanks are skipped and the next content line decides; an unrecognized prefix is plain <= 3 space indentation, not a container, and keeps the unbounded scan (blank lines and fences stay math content). Regression tests: the quoted example (prose stays prose, the later equation keeps its own opener), a list-container variant, a blank-line/new-quote guard, plus two in-container close locks — the first three fail on the pre-fix scan. Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(android): render mermaid fences as offline diagrams Port the web MermaidDiagram component to Android chat markdown. A fence whose language is exactly `mermaid` (case-sensitive, like the web's MARKDOWN_COMPONENTS_BY_LANGUAGE key) now dispatches to MermaidDiagramView instead of the plain code block; every other fence keeps the CodeBlock path. Rendering runs in a hardened offline WebView fed a self-built HTML document against bundled assets/mermaid/mermaid.min.js (Mermaid 11.14.0, curl-fetched, sha256-identical to the web app's locked dependency). That dist file is a self-contained classic script assigning globalThis mermaid - no imports, no runtime fetches - so no ES-module/CORS workaround is needed. The view shares the KaTeX skeleton: network stack blocked, file/content access off, asset URLs through the file:///android_asset/mermaid/ base URL (OfflineMathWebViewClient generalized to OfflineMarkdownWebViewClient, no behavior change). Behavior mirrors the web component line by line: initialize with startOnLoad:false, securityLevel:'strict', suppressErrorRendering:true and the web's dark/light themeVariables palettes verbatim (theme flips re-render); the validate-then-render gate parses with suppressErrors first and never calls render() after a failed validation, re-parsing once without suppression only to surface a human-readable reason; svg element ids are per-instance (`mermaid-<n>`, web useId) so the scoped styles mermaid emits cannot collide across diagrams in one message; wide diagrams scroll horizontally inside the document while the svg is centered at max-width:100% and height:auto. The code header (language chip + copy) stays above the body like the web's retained DefaultCodeBlock header; until the diagram renders - and on failure - the raw source is shown below it (the block's source exit), with the failure notice appearing only for actual errors so the loading window never flashes a render-error line. mermaidFallbackUi maps state to those surfaces as a pure function. 15 JVM tests cover dispatch, offline-ness, palettes, security flags, the validation gate structure, id uniqueness, generation filtering, script-breakout safety and the fallback mapping; the driver's runtime semantics were additionally validated against the real bundle in jsdom (flowchart/sequence render, invalid source surfaces the parse reason, hostile labels are rejected/sanitized under strict). Co-Authored-By: Claude Code <noreply@anthropic.com> via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(android): convert CSS pixel heights correctly in the mermaid WebView Both height reporters feeding MermaidDiagramView — the document bridge's report() (documentElement/body scrollHeight) and OfflineMarkdownWebViewClient's onPageFinished re-measure — return CSS pixels, but the rendered branch ran the value through with(density) { heightPx.toDp() }, which treats it as Android physical pixels and divides by display density: on a 3x display a diagram measuring 180 CSS px received a 60dp box and was clipped into an unnecessarily scrolling WebView. Fix it exactly like the KaTeX base now does: the document pins `width=device-width, initial-scale=1` (making 1 CSS px = 1 dp at the default WebView scale an explicit property of the document rather than a WebView default), and the reported value crosses the boundary through the shared density-independent cssPxToDp helper — extracted as the pure mermaidRenderedHeightDp so the composable no longer holds any density conversion at all, keeping both markdown renderers on one boundary contract. (The KaTeXMathBlock repeat of the same bug is fixed by the rebased base; MathWebView.kt arrives converted already.) JVM tests: the viewport pin is asserted against the built document (demonstrated failing on the pre-fix template) and the conversion math is driven through the pure helper — 180 CSS px stays 180dp because the boundary carries no density parameter, mirroring the base's MathDocumentTest contract. Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(android): generalize generated media blocks to video/audio/file The hub's /generated-images/:id endpoint already serves any mime type (video, audio, arbitrary files arrive as the same generated-image wire block with a mimeType), but the Android chat rendered every block as an image. This ports the web GeneratedImageCard generalization so the card routes by display intent, exactly like web generatedInlineMedia.ts: - mimeType routing is the web's literal prefix check: video/… gets a player, audio/… an audio player, image/… or null keep the existing image treatment (unchanged AsyncImage thumbnail + tap-to-zoom dialog), everything else is a file card (no separate "unsupported" class — unknown mimes ARE the file UI, matching web G3/G8). - non-image media never downloads on its own: "Load video" / "Load audio" / "Prepare download" gate buttons (web's explicit-intent rule G4; English labels verbatim from the web card), pulsing skeleton while fetching (G7), and the shared "{label} is unavailable. {error}" error line (G8). The wire carries no tiny/poster fields, so video renders bare — nothing to special-case. - every kind now sits in the web's G14 card shell with the localized "{label}: {fileName}" hint header; images additionally surface the error line on Coil failure instead of a silent empty hole. - downloads go through the same authed OkHttp client Coil uses (JWT + silent 401 re-auth + ETag disk cache), staged into a temp file and atomically renamed under cache/generated-media/; a completed file short-circuits later fetches (immutable, ETag-stable content) and non-2xx maps to "HTTP <code>" exactly like the web's ApiError. - video plays in-app via framework VideoView + MediaController (no new media dependencies: Media3 is not on the classpath and pulling it in for this card is not worth the MB); audio is a compact play/pause + scrub + m:ss row over MediaPlayer (web's native <audio> chrome degraded: volume/speed omitted, no waveform — web has none); files get Open (ACTION_VIEW over the existing FileProvider, new generated-media cache path) and Save (ACTION_CREATE_DOCUMENT picker) outlets in place of the browser download link. - ChatMedia gains a nullable fetchGeneratedMedia field (default null: previews/tests degrade to the unavailable line, so stack-only call sites merge unchanged). 17 new strings added to en/ru/zh-CN in one commit, mirroring en key order (KEYSYNC clean; zh count equal — its pre-existing regional order drift is untouched). 10 JVM tests cover routing (including case sensitivity and null-mime), mount-gating, label/action mapping, cache file name sanitizing (path traversal), the MockWebServer round-trip with status mapping + cached-file short-circuit, and the time formatter. Gate: :app:testDebugUnitTest :core:data:test :core:protocol:test :app:lintDebug :app:compileDebugAndroidTestKotlin BUILD SUCCESSFUL. Co-Authored-By: Claude Code <noreply@anthropic.com> via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(android): refine generic file MIME types from the filename The file card passed the wire mimeType straight through to ACTION_VIEW, substituting application/octet-stream only when the wire type was null (r4370795783). Passing octet-stream explicitly defeats Android's viewer matching: a PDF viewer registered for application/pdf is not matched by an intent whose type says application/octet-stream, so PDFs (and every other ordinary file whose hub type was octet-stream or missing) opened with no eligible activity. resolveFileMimeType now passes a specific wire type through untouched, but when the wire type is missing, empty, or octet-stream (compared case-insensitively) it re-derives the type from the original filename's extension through an injected resolver — android.webkit.MimeTypeMap at the call site, following the established AttachmentPreparer / AndroidShareIntake pattern (lowercased extension, slash/wildcard sanity check on the resolved value). Unknown extensions keep the generic octet-stream fallback. The resolved type feeds both outlets: the Open ACTION_VIEW intent and the Save ACTION_CREATE_DOCUMENT contract. The resolver is a required parameter rather than a default, which keeps GeneratedMedia.kt free of android.* imports and forces the seam: 3 JVM tests drive it with a fake table (pdf->application/pdf via extension for null/octet-stream/empty wire types; unknown extension and no extension -> octet-stream fallback; specific wire types pass through untouched even when the extension would map elsewhere). All three fail on the pre-fix code by construction — resolveFileMimeType did not exist and the null-wire PDF case asserted the old octet-stream handoff. Gate: :app:testDebugUnitTest --tests GeneratedMediaTest BUILD SUCCESSFUL (13 tests, 0 failures). Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(android): bound generated media cache names by UTF-8 bytes sanitizedGeneratedMediaFileName capped the stem at 96 UTF-16 chars and relied on that alone (r4370795787). Android filename limits are byte limits (NAME_MAX 255): 80 hanzi + ".pdf" is a 122-char / 281-byte component once the UUID imageId prefix is attached (verified against the pre-fix logic: 36-byte id + 1 + 240 + 4 = 281 bytes), so long Chinese names failed the atomic cache rename outright. The complete component — id prefix + stem + extension — is now assembled under a 255-byte UTF-8 budget, with pathological ids and extensions capped at 64/32 bytes so the stem always keeps room. The stem keeps its historical 96-char cap (ASCII names keep their exact prior shape), bytes beyond the budget are cut from the stem only, on code-point boundaries, and the extension always survives intact. The char-level whitelist already drops surrogate halves (a lone half is never a letter), so every surviving char is one complete BMP code point; the truncation helpers are additionally pair-safe for any future code-point-aware whitelist. JVM tests: the reviewer's UUID + 80-hanzi ".pdf" case lands at <= 255 bytes with the extension and id prefix preserved (red on the pre-fix logic, which produced exactly 281); ".tar.gz"-style extensions survive stem truncation; a battery of multibyte names re-decode byte-identically under the cap; ASCII names keep their historical shapes ("i-" + 96 a's, "img-1-media", "id-x.bin", "i-截图01.png"). Gate: :app:testDebugUnitTest --tests GeneratedMediaTest BUILD SUCCESSFUL (16 tests, 0 failures). Co-Authored-By: Claude Code <noreply@anthropic.com> * test(android): cover audio playback wiring and the file outlets' types The play/pause/seek decisions and the MediaPlayer lifecycle lived inline in the audio composable, which made them unreachable from JVM tests (no emulator here; androidTest only compile-checks). Extract them into GeneratedAudioSession over a GeneratedAudioPlayer seam — the app side adapts android.media.MediaPlayer, tests pass a scriptable fake — and the card now collects the session's flows, with DisposableEffect.onDispose forwarding to session.release(). JVM coverage through the fake: - prepare wires the data source + prepareAsync and reports duration on the prepared callback; pre-preparation toggles/seeks stay inert; - the toggle maps to start/pause (turbine on the playing flow) and natural completion parks the row; - seekToFraction lands fraction*duration and clamps to [0, duration], reading the position back afterwards; - pollPosition only reads while playing (the 250 ms LaunchedEffect); - release — the dispose hook — releases the framework player exactly once across double-dispose, stops playback, and every later control call is inert (a released MediaPlayer throws); - player errors and a failing data source both map to the failed line and the row goes dead. The file card's Open/Save construction moves behind generatedFileOutlets so a JVM test pins that ACTION_VIEW and ACTION_CREATE_DOCUMENT both carry the *resolved* MIME type (inferred pdf, generic fallback, specific wire passthrough) plus the suggested save name — android.content.Intent is not on the unit-test classpath. A MockWebServer fetch with the reviewer's 80-hanzi + UUID name proves the byte-bounded component really round-trips the local filesystem: under 255 bytes, extension kept, no staging litter beside the final file. These tests fail on the pre-change code by construction: the session, seam, and outlets did not exist and the logic was not reachable from the JVM. Explicit loading (loadsOnMount gate), authenticated caching (hubGraph.session.imageClient: JWT + silent 401 re-auth + ETag cache), and download cleanup (staged temp deleted on failure, atomic rename on success) are untouched — only their test surface grew. Gate: :app:testDebugUnitTest --tests GeneratedMediaTest BUILD SUCCESSFUL (24 tests, 0 failures). Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: HAPI <noreply@hapi.run>
694 lines
47 KiB
XML
694 lines
47 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<resources>
|
||
<string name="app_name">HAPI</string>
|
||
|
||
<!-- Markdown / code / diff rendering (B-M2d1) -->
|
||
<string name="code_copy">Copy</string>
|
||
<string name="code_copied">Copied</string>
|
||
<string name="code_plain_fallback">text</string>
|
||
<string name="mermaid_render_error">Could not render diagram.</string>
|
||
<string name="diff_binary_file">Binary file not shown</string>
|
||
<string name="diff_show_more">Show %1$d more lines</string>
|
||
<string name="diff_collapse">Collapse</string>
|
||
|
||
<!-- Pairing (B-M1d) -->
|
||
<string name="pairing_title">Pair with your hub</string>
|
||
<string name="pairing_intro">HAPI is self-hosted: your coding agents run on your own machines behind a HAPI hub you operate. Pair this app with that hub to watch and steer them from your phone.</string>
|
||
<string name="pairing_hint">Scan the “Companion app” QR code your hub prints on startup (with --relay), or enter the hub URL and access token by hand.</string>
|
||
<string name="pairing_scan_qr">Scan QR code</string>
|
||
<string name="pairing_manual_entry">Enter manually</string>
|
||
<string name="pairing_notice_dismiss">Dismiss</string>
|
||
<string name="pairing_error_dismiss">Dismiss</string>
|
||
<string name="pairing_validating">Checking hub…</string>
|
||
<string name="pairing_confirm_title">Pair with this hub?</string>
|
||
<string name="pairing_confirm_already">This hub is already paired on this device.</string>
|
||
<string name="pairing_confirm_pair">Pair now</string>
|
||
<string name="pairing_confirm_switch">Use existing pairing</string>
|
||
<string name="pairing_confirm_repair">Re-pair with the new code</string>
|
||
<string name="pairing_confirm_cancel">Cancel</string>
|
||
<string name="pairing_invalid_link">That pairing link is invalid, incomplete, or does not use HTTPS.</string>
|
||
<string name="pairing_back">Back</string>
|
||
|
||
<!-- Manual entry -->
|
||
<string name="pairing_manual_title">Manual pairing</string>
|
||
<string name="pairing_manual_hint">Find both values in the hub terminal on startup, or in the web app under Settings → Companion pairing.</string>
|
||
<string name="pairing_hub_url_label">Hub URL</string>
|
||
<string name="pairing_hub_url_placeholder">https://hub.example.com</string>
|
||
<string name="pairing_token_label">Access token</string>
|
||
<string name="pairing_token_placeholder">Paste the access token</string>
|
||
<string name="pairing_pair_button">Pair</string>
|
||
|
||
<!-- QR scan -->
|
||
<string name="pairing_scan_title">Scan pairing QR</string>
|
||
<string name="pairing_scan_prompt">Point the camera at the pairing QR code</string>
|
||
<string name="pairing_scan_not_pairing_qr">That QR code is not a valid HTTPS HAPI pairing code. Scan one of the two QR codes your hub prints (Companion app or Web app).</string>
|
||
<string name="pairing_scan_again">Scan again</string>
|
||
<string name="pairing_scan_permission_rationale">Camera access is needed to scan the pairing QR code. You can also pair manually instead.</string>
|
||
<string name="pairing_scan_grant_camera">Grant camera access</string>
|
||
|
||
<!-- Home (session list top bar + hub chores) -->
|
||
<string name="home_menu">Menu</string>
|
||
<string name="home_settings">Settings</string>
|
||
<string name="home_hub">Hub</string>
|
||
<string name="home_hub_menu">Hubs and settings</string>
|
||
<string name="home_switch_hub">Switch hub</string>
|
||
<string name="home_pair_another">Pair another hub…</string>
|
||
<string name="home_sign_out">Sign out</string>
|
||
<string name="home_sign_out_message">Remove this hub pairing? The stored credentials are deleted from this device (the hub itself is untouched).</string>
|
||
<string name="home_cancel">Cancel</string>
|
||
|
||
<!-- New session (B-M3d) -->
|
||
<string name="new_session_title">New session</string>
|
||
<string name="new_session_back">Back</string>
|
||
<string name="new_session_fab">New session</string>
|
||
<string name="new_session_machine">Machine</string>
|
||
<string name="new_session_machines_loading">Loading machines…</string>
|
||
<string name="new_session_no_machines">No machines online</string>
|
||
<string name="new_session_runner_spawn_error">Runner last spawn error: %1$s</string>
|
||
<string name="new_session_directory">Directory</string>
|
||
<string name="new_session_directory_placeholder">/path/to/project</string>
|
||
<string name="new_session_browse">Browse directories</string>
|
||
<string name="directory_browser_choose_directory">Choose directory</string>
|
||
<string name="directory_browser_up">Go to parent directory</string>
|
||
<string name="directory_browser_refresh">Refresh</string>
|
||
<string name="directory_browser_show_hidden">Show hidden</string>
|
||
<string name="directory_browser_empty">No subdirectories</string>
|
||
<string name="directory_browser_select_current">Select current directory</string>
|
||
<string name="new_session_recent_paths">Recent paths</string>
|
||
<string name="new_session_type">Session type</string>
|
||
<string name="new_session_type_simple">Simple</string>
|
||
<string name="new_session_type_simple_desc">Use selected directory as-is</string>
|
||
<string name="new_session_type_worktree">Worktree</string>
|
||
<string name="new_session_type_worktree_desc">Create a new git worktree next to the repo</string>
|
||
<string name="new_session_worktree_name">Worktree name</string>
|
||
<string name="new_session_worktree_name_placeholder">feature-x (optional)</string>
|
||
<string name="new_session_agent">Agent</string>
|
||
<string name="new_session_agent_availability_loading">Checking installed Agents…</string>
|
||
<string name="new_session_retry">Retry</string>
|
||
<string name="new_session_model">Model</string>
|
||
<string name="new_session_effort">Effort</string>
|
||
<string name="new_session_reasoning_effort">Reasoning effort</string>
|
||
<string name="new_session_permission_mode">Permission mode</string>
|
||
<string name="new_session_permission_managed">Managed by agent</string>
|
||
<string name="new_session_permission_managed_desc">This agent manages its own permissions. YOLO mode is not available.</string>
|
||
<string name="new_session_grok_auto_unavailable">unavailable</string>
|
||
<string name="new_session_grok_auto_unavailable_desc">Grok did not enable Auto permissions for this account or CLI build.</string>
|
||
<string name="new_session_yolo">YOLO mode</string>
|
||
<string name="new_session_yolo_title">Bypass approvals and sandbox</string>
|
||
<string name="new_session_yolo_desc">Uses dangerous agent flags when spawning.</string>
|
||
<string name="new_session_yolo_maps_to">Applies native %1$s mode.</string>
|
||
<string name="new_session_collaboration_mode">Collaboration mode</string>
|
||
<string name="new_session_copilot_agent_mode">Agent mode</string>
|
||
<string name="new_session_fast_mode">Fast mode</string>
|
||
<string name="new_session_fast_mode_standard">Standard</string>
|
||
<string name="new_session_fast_mode_fast">Fast</string>
|
||
<string name="new_session_loading">Loading…</string>
|
||
<string name="new_session_create">Create</string>
|
||
<string name="new_session_creating">Creating…</string>
|
||
<string name="new_session_create_and_make_directory">Create and make directory</string>
|
||
|
||
<!-- Settings scaffold (B-M4e) -->
|
||
<string name="settings_title">Settings</string>
|
||
<string name="settings_category_general">General</string>
|
||
<string name="settings_category_general_summary">Appearance, language, and about</string>
|
||
<string name="settings_back">Back</string>
|
||
<string name="settings_cancel">Cancel</string>
|
||
<string name="settings_retry">Retry</string>
|
||
<string name="settings_load_error">Could not load this dashboard.</string>
|
||
<string name="settings_owner_only">This dashboard is only available to the hub owner (default namespace).</string>
|
||
|
||
<string name="settings_section_appearance">Appearance</string>
|
||
<string name="settings_theme">Theme</string>
|
||
<string name="settings_theme_system">Follow system</string>
|
||
<string name="settings_theme_light">Light</string>
|
||
<string name="settings_theme_dark">Dark</string>
|
||
<string name="settings_theme_oled">OLED black</string>
|
||
<string name="settings_dynamic_color">Material You colors</string>
|
||
<string name="settings_dynamic_color_description">Derive app colors from your wallpaper.</string>
|
||
<string name="settings_dynamic_color_oled_note">Not available with OLED black.</string>
|
||
|
||
<string name="settings_section_language">Language</string>
|
||
<string name="settings_language">App language</string>
|
||
<string name="settings_language_system">Follow system</string>
|
||
|
||
<string name="settings_section_insights">Insights</string>
|
||
<string name="settings_usage_summary">Token usage across agents and models</string>
|
||
<string name="settings_storage_summary">Hub database size on disk</string>
|
||
|
||
<string name="settings_section_about">About</string>
|
||
<string name="settings_app_version">App version</string>
|
||
<string name="settings_protocol_version">Protocol version</string>
|
||
<string name="settings_hub">Hub</string>
|
||
<string name="settings_hub_checking">Checking hub…</string>
|
||
<string name="settings_hub_health">Status: %1$s · protocol v%2$d</string>
|
||
<string name="settings_hub_unreachable">Hub unreachable — tap to retry.</string>
|
||
|
||
<!-- Usage dashboard -->
|
||
<string name="settings_usage">Usage</string>
|
||
<string name="settings_usage_range_7d">7 days</string>
|
||
<string name="settings_usage_range_30d">30 days</string>
|
||
<string name="settings_usage_range_all">All time</string>
|
||
<string name="settings_usage_total">Total tokens</string>
|
||
<string name="settings_usage_uncached">Uncached</string>
|
||
<string name="settings_usage_input">Input</string>
|
||
<string name="settings_usage_output">Output</string>
|
||
<string name="settings_usage_cache_read">Cache read</string>
|
||
<string name="settings_usage_cache_creation">Cache creation</string>
|
||
<string name="settings_usage_cache_hit_rate">Cache hit rate</string>
|
||
<string name="settings_usage_requests">Requests</string>
|
||
<string name="settings_usage_daily_title">Daily tokens</string>
|
||
<string name="settings_usage_tooltip">%1$s tokens · %2$d req · in %3$s / out %4$s</string>
|
||
<string name="settings_usage_tooltip_empty">0 tokens</string>
|
||
<string name="settings_usage_by_agent">By agent</string>
|
||
<string name="settings_usage_by_model">By model</string>
|
||
<string name="settings_usage_bucket_details">%1$d requests · in %2$s · out %3$s</string>
|
||
<string name="settings_usage_sessions">Sessions with usage: %1$d</string>
|
||
<string name="settings_usage_empty">No usage recorded in this period.</string>
|
||
|
||
<!-- Storage dashboard -->
|
||
<string name="settings_storage">Storage</string>
|
||
<string name="settings_storage_description">Disk footprint of the hub\'s SQLite database (database, write-ahead log, shared memory).</string>
|
||
<string name="settings_storage_chart_title">SQLite files</string>
|
||
<string name="settings_storage_chart_empty">No storage data reported.</string>
|
||
<string name="settings_storage_database">Database</string>
|
||
<string name="settings_storage_wal">Write-ahead log</string>
|
||
<string name="settings_storage_shm">Shared memory</string>
|
||
<string name="settings_storage_total">Total</string>
|
||
<string name="settings_storage_path">Path</string>
|
||
<string name="settings_storage_refresh">Refresh</string>
|
||
<string name="settings_storage_refreshing">Refreshing…</string>
|
||
|
||
<!-- Push notifications (B-M4a) -->
|
||
<string name="channel_permission_requests">Permission requests</string>
|
||
<string name="channel_permission_requests_desc">An agent is waiting for you to allow or deny a tool call</string>
|
||
<string name="channel_input_requests">Questions for you</string>
|
||
<string name="channel_input_requests_desc">An agent needs you to answer a question in the session</string>
|
||
<string name="channel_ready">Agent ready</string>
|
||
<string name="channel_ready_desc">An agent finished and is waiting for input</string>
|
||
<string name="channel_task_notifications">Task notifications</string>
|
||
<string name="channel_task_notifications_desc">Task completed or failed, and other updates</string>
|
||
<string name="notif_action_allow">Allow</string>
|
||
<string name="notif_action_deny">Deny</string>
|
||
<string name="notif_action_reply">Reply</string>
|
||
<string name="notif_action_dismiss">Dismiss</string>
|
||
<string name="notif_reply_hint">Message</string>
|
||
<string name="notif_allowing">Allowing…</string>
|
||
<string name="notif_denying">Denying…</string>
|
||
<string name="notif_sending">Sending…</string>
|
||
<string name="notif_allowed">Allowed</string>
|
||
<string name="notif_denied">Denied</string>
|
||
<string name="notif_reply_sent">Reply sent</string>
|
||
<string name="notif_already_handled">Already handled</string>
|
||
<string name="notif_session_inactive">Session is no longer active — open the app to resume it</string>
|
||
<string name="notif_session_not_found">Session not found on any paired hub</string>
|
||
<string name="notif_action_failed">Couldn’t reach the hub — open the app to respond</string>
|
||
<string name="notif_reply_failed">Reply not sent — open the app to try again</string>
|
||
|
||
<!-- Session list (B-M2b / B-M3ce, extracted in B-M5a) -->
|
||
<string name="sessions_section_pinned">Pinned</string>
|
||
<string name="sessions_section_sessions">Sessions</string>
|
||
<string name="sessions_filter_all">All</string>
|
||
<string name="sessions_filter_unknown_machine">Unknown machine</string>
|
||
<string name="sessions_offline_banner">Offline — showing cached sessions</string>
|
||
<string name="sessions_section_recent">Recent</string>
|
||
<string name="sessions_status_connecting">Connecting…</string>
|
||
<string name="sessions_status_reconnecting">Reconnecting…</string>
|
||
<string name="sessions_status_paused">Paused</string>
|
||
<string name="sessions_offline_updated">Offline · updated %1$s</string>
|
||
<string name="sessions_offline_retry">Retry</string>
|
||
<string name="sessions_action_mark_read">Mark as read</string>
|
||
<string name="sessions_unread">Unread</string>
|
||
<string name="sessions_presence_connected">Connected</string>
|
||
<string name="sessions_presence_running">Running</string>
|
||
<string name="sessions_error_mark_read">Couldn’t mark as read</string>
|
||
<string name="sessions_search_hint">Search sessions</string>
|
||
<string name="sessions_search_open">Search sessions</string>
|
||
<string name="sessions_search_close">Close search</string>
|
||
<string name="sessions_search_no_results">No sessions matching “%1$s”</string>
|
||
<string name="sessions_search_no_results_hint">Try another term, or clear the search.</string>
|
||
<string name="sessions_empty_loading_title">Loading sessions…</string>
|
||
<string name="sessions_empty_offline_title">Hub unreachable</string>
|
||
<string name="sessions_empty_title">No sessions yet</string>
|
||
<string name="sessions_empty_loading_hint">Fetching the session list from the hub.</string>
|
||
<string name="sessions_empty_offline_hint">Pull to retry once you are back online.</string>
|
||
<string name="sessions_empty_hint">Start an agent with the hapi CLI and it will appear here.</string>
|
||
<string name="sessions_badge_needs_input">needs input</string>
|
||
<string name="sessions_badge_approve">approve %1$s</string>
|
||
<string name="sessions_badge_pending">pending</string>
|
||
<string name="sessions_action_unpin">Unpin</string>
|
||
<string name="sessions_action_pin_project">Pin to project</string>
|
||
<string name="sessions_action_pin_global">Pin globally</string>
|
||
<string name="sessions_action_rename">Rename</string>
|
||
<string name="sessions_action_reopen">Reopen</string>
|
||
<string name="sessions_action_archive">Archive</string>
|
||
<string name="sessions_action_delete">Delete</string>
|
||
<string name="sessions_error_pin">Pin failed</string>
|
||
<string name="sessions_error_archive">Archive failed</string>
|
||
<string name="sessions_error_rename">Rename failed</string>
|
||
<string name="sessions_error_delete">Delete failed</string>
|
||
<string name="sessions_error_reopen">Reopen failed</string>
|
||
<string name="sessions_error_machines">Could not load machines</string>
|
||
<string name="sessions_error_delete_active">Session is still active — archive it first</string>
|
||
<string name="sessions_reopen_failed_fallback">Failed to reopen session</string>
|
||
<string name="sessions_rename_title">Rename session</string>
|
||
<string name="sessions_rename_placeholder">Session name</string>
|
||
<string name="sessions_delete_title">Delete session?</string>
|
||
<string name="sessions_delete_message">“%1$s” and its message history will be removed from the hub permanently. Active sessions must be archived first.</string>
|
||
<string name="sessions_cancel">Cancel</string>
|
||
<string name="sessions_age_now">now</string>
|
||
|
||
<!-- Chat screen chrome (B-M2c/B-M3, extracted in B-M5a) -->
|
||
<string name="chat_back">Back</string>
|
||
<string name="chat_open_files">Session files</string>
|
||
<string name="chat_open_scratchlist">Scratchlist</string>
|
||
<string name="chat_open_scratchlist_count">Scratchlist (%1$d)</string>
|
||
<string name="chat_open_settings">Session settings</string>
|
||
<string name="chat_session_actions">Session actions</string>
|
||
<string name="chat_scratchlist_badge">Scratchlist</string>
|
||
<string name="chat_inactive_bar">Session inactive — send to resume, or</string>
|
||
<string name="chat_retry">Retry</string>
|
||
<string name="chat_loading_messages">Loading messages…</string>
|
||
<string name="chat_loading_older">Loading older messages…</string>
|
||
<string name="chat_load_failed_title">Couldn’t load this session</string>
|
||
<string name="chat_load_failed_hint">Check the connection to your hub and try again.</string>
|
||
<string name="chat_empty_title">No messages yet</string>
|
||
<string name="chat_empty_hint">Messages will appear here as the agent works.</string>
|
||
<string name="chat_new_messages_one">1 new message ↓</string>
|
||
<string name="chat_new_messages_many">%1$d new messages ↓</string>
|
||
|
||
<!-- Chat snackbar notices (semantic ChatNotice resolution) -->
|
||
<string name="chat_notice_no_transcription">No transcription provider configured on hub</string>
|
||
<string name="chat_notice_mic_permission">Microphone permission is needed for dictation</string>
|
||
<string name="chat_notice_camera_permission">Camera permission is needed to take a photo</string>
|
||
<string name="chat_notice_attachment_too_large">%1$s is over the 50 MB upload limit</string>
|
||
<string name="chat_notice_attachment_unreadable">Couldn’t read %1$s</string>
|
||
<string name="chat_notice_draft_parked">Draft parked to scratchlist</string>
|
||
<string name="chat_notice_scratchlist_full">Scratchlist is full (200 entries)</string>
|
||
<string name="chat_notice_park_failed">Couldn’t park the draft — check the hub connection</string>
|
||
<string name="chat_notice_attachments_uploading">Attachments are still uploading — wait, or retry/remove the failed ones</string>
|
||
<string name="chat_notice_resume_failed">Session is inactive and could not be resumed</string>
|
||
<string name="chat_notice_abort_failed">Failed to abort</string>
|
||
<string name="chat_notice_rename_failed">Failed to rename session</string>
|
||
<string name="chat_notice_delete_failed">Failed to delete session</string>
|
||
<string name="chat_notice_cancel_failed">Failed to cancel queued message</string>
|
||
<string name="chat_notice_edit_kept_draft">Message cancelled — kept your current draft</string>
|
||
<string name="chat_notice_already_delivered">Already delivered to the agent</string>
|
||
<string name="chat_notice_steer_failed">Failed to steer message</string>
|
||
<string name="chat_notice_request_already_handled">Request was already handled</string>
|
||
<string name="chat_notice_request_failed">Request failed</string>
|
||
<string name="chat_notice_models_failed">Failed to load models</string>
|
||
<string name="chat_notice_config_failed">Failed to update session</string>
|
||
|
||
<!-- Composer (B-M3a/ce/f) -->
|
||
<string name="chat_composer_placeholder">Message the agent…</string>
|
||
<string name="chat_attachment_uploading">Uploading…</string>
|
||
<string name="chat_attachment_failed_retry">Failed — tap to retry</string>
|
||
<string name="chat_recording">● Recording… %1$s</string>
|
||
<string name="chat_cancel">Cancel</string>
|
||
<string name="chat_park_draft">Park draft to scratchlist</string>
|
||
<string name="chat_composer_add_attachment">Add attachment</string>
|
||
<string name="chat_composer_mic">Start dictation</string>
|
||
<string name="chat_composer_stop_recording">Stop recording</string>
|
||
<string name="chat_composer_send">Send</string>
|
||
<string name="chat_composer_abort">Stop the current turn</string>
|
||
<string name="chat_send_steer">Send & steer into current turn</string>
|
||
<string name="chat_queued_one">1 queued message</string>
|
||
<string name="chat_queued_many">%1$d queued messages</string>
|
||
<string name="chat_queued_scheduled">Scheduled · %1$s</string>
|
||
<string name="chat_queued_steer">Steer</string>
|
||
<string name="chat_queued_edit">Edit</string>
|
||
<string name="chat_picker_title">Attach</string>
|
||
<string name="chat_picker_photos">Photo library</string>
|
||
<string name="chat_picker_camera">Camera</string>
|
||
<string name="chat_picker_files">Files</string>
|
||
|
||
<!-- Dictation errors (B-M3ce) -->
|
||
<string name="chat_dictation_start_failed">Could not start recording</string>
|
||
<string name="chat_dictation_hub_unreachable">Could not reach the hub</string>
|
||
<string name="chat_dictation_recording_failed">Audio recording failed</string>
|
||
<string name="chat_dictation_no_audio">No audio was recorded</string>
|
||
<string name="chat_dictation_failed">Transcription failed</string>
|
||
|
||
<!-- Session config sheet (B-M3b) -->
|
||
<string name="chat_config_offline_note">Session is offline — changes apply after it resumes or may be rejected.</string>
|
||
<string name="chat_config_terminal_note">Session is controlled from the terminal — config changes will be rejected.</string>
|
||
<string name="chat_config_permission_mode">Permission mode</string>
|
||
<string name="chat_config_model">Model</string>
|
||
<string name="chat_config_loading_models">Loading models…</string>
|
||
<string name="chat_config_models_unavailable">Model list unavailable for this session.</string>
|
||
<string name="chat_config_effort">Effort</string>
|
||
|
||
<!-- Chat blocks (B-M2c/d) -->
|
||
<string name="chat_tool_awaiting_approval">Awaiting approval</string>
|
||
<string name="chat_tool_awaiting_approval_badge">⏳ Awaiting approval</string>
|
||
<string name="chat_tool_approved">✓ Approved</string>
|
||
<string name="chat_tool_approved_for_session">✓ Approved for session</string>
|
||
<string name="chat_tool_approved_allow_all_edits">✓ Approved: allow all edits</string>
|
||
<string name="chat_tool_denied">✕ Denied</string>
|
||
<string name="chat_tool_aborted">✕ Aborted</string>
|
||
<string name="chat_tool_resolved">Resolved in Codex</string>
|
||
<string name="chat_tool_canceled">— Canceled</string>
|
||
<string name="chat_tool_status_pending">pending</string>
|
||
<string name="chat_tool_status_error">error</string>
|
||
<string name="chat_agent_steps_one">1 agent step</string>
|
||
<string name="chat_agent_steps_many">%1$d agent steps</string>
|
||
<string name="chat_group_tools_one">1 tool</string>
|
||
<string name="chat_group_tools_many">%1$d tools</string>
|
||
<string name="chat_before">Before</string>
|
||
<string name="chat_after">After</string>
|
||
<string name="chat_edit_n_of_m">Edit %1$d/%2$d</string>
|
||
<string name="chat_empty_snippet">(empty)</string>
|
||
<string name="chat_result">Result</string>
|
||
<string name="chat_result_error">Result · error</string>
|
||
<string name="chat_reasoning_expanded">💭 Reasoning ▾</string>
|
||
<string name="chat_reasoning_collapsed">💭 Reasoning ▸</string>
|
||
<string name="chat_not_delivered_retry">Not delivered — tap to retry</string>
|
||
<string name="chat_not_delivered">Not delivered</string>
|
||
<string name="chat_review_title">Code review</string>
|
||
<string name="chat_review_findings_one">1 finding</string>
|
||
<string name="chat_review_findings_many">%1$d findings</string>
|
||
|
||
<!-- Permission footers (B-M3b) -->
|
||
<string name="chat_perm_allow">Allow</string>
|
||
<string name="chat_perm_deny">Deny</string>
|
||
<string name="chat_perm_abort">Abort</string>
|
||
<string name="chat_perm_allow_for_session">Allow for this session</string>
|
||
<string name="chat_perm_allow_all_edits">Allow all edits</string>
|
||
<string name="chat_perm_already_handled">Already handled elsewhere</string>
|
||
<string name="chat_perm_type_answer">Type your answer…</string>
|
||
<string name="chat_perm_add_note">Add a note…</string>
|
||
<string name="chat_perm_none_of_the_above">None of the above</string>
|
||
<string name="chat_perm_other_note_optional">Optionally, add details in notes.</string>
|
||
<string name="chat_perm_open_signin_failed">Could not open the sign-in page. Check that a browser is installed and try again.</string>
|
||
<string name="chat_question_awaiting">Awaiting response</string>
|
||
<string name="chat_question_answered">Answered</string>
|
||
<string name="chat_question_handled">Question handled</string>
|
||
<string name="chat_question_canceled">Question canceled</string>
|
||
<string name="chat_question_failed">Question failed</string>
|
||
<string name="chat_question_submitting">Submitting answer…</string>
|
||
<string name="chat_question_your_answer">Your answer</string>
|
||
<string name="chat_question_progress_a11y">Question %1$d of %2$d</string>
|
||
<string name="chat_question_details">Details</string>
|
||
<string name="chat_question_unavailable">This question could not be displayed. Open details to inspect the request.</string>
|
||
<string name="chat_question_select_all">Select all that apply</string>
|
||
<string name="chat_question_optional">Optional</string>
|
||
<string name="chat_question_other_answer">Other answer</string>
|
||
<string name="chat_question_hide_note">Hide note</string>
|
||
<string name="chat_question_previous">Previous question</string>
|
||
<string name="chat_question_submit">Submit answer</string>
|
||
<string name="chat_question_next">Next question</string>
|
||
<string name="chat_question_recommended">Recommended</string>
|
||
|
||
<!-- External links (B-M2d) -->
|
||
<string name="chat_link_open_title">Open link?</string>
|
||
<string name="chat_link_open">Open</string>
|
||
<string name="chat_link_no_app">No app can open this link</string>
|
||
|
||
<!-- Tool card titles (ToolCardPresentation; web knownTools registry) -->
|
||
<string name="tool_terminal">Terminal</string>
|
||
<string name="tool_read_file">Read file</string>
|
||
<string name="tool_read_notebook">Read notebook</string>
|
||
<string name="tool_edit_file">Edit file</string>
|
||
<string name="tool_edit_notebook">Edit notebook</string>
|
||
<string name="tool_write_file">Write file</string>
|
||
<string name="tool_search_files">Search files</string>
|
||
<string name="tool_search_content">Search content</string>
|
||
<string name="tool_list_files">List files</string>
|
||
<string name="tool_web_fetch">Web fetch</string>
|
||
<string name="tool_web_search">Web search</string>
|
||
<string name="tool_task">Task</string>
|
||
<string name="tool_launch_agent">Launch Agent</string>
|
||
<string name="tool_agent_named">Agent: %1$s</string>
|
||
<string name="tool_agent">Agent</string>
|
||
<string name="tool_spawn_agent">Spawn agent</string>
|
||
<string name="tool_resume_agent">Resume agent</string>
|
||
<string name="tool_wait_agent">Wait for agent</string>
|
||
<string name="tool_close_agent">Close agent</string>
|
||
<string name="tool_interrupt_agent">Interrupt agent</string>
|
||
<string name="tool_broadcast">Broadcast</string>
|
||
<string name="tool_shutdown">Shutdown: %1$s</string>
|
||
<string name="tool_shutdown_fallback_recipient">agent</string>
|
||
<string name="tool_shutdown_response">Shutdown Response</string>
|
||
<string name="tool_message_named">Message: %1$s</string>
|
||
<string name="tool_message_agent">Message agent</string>
|
||
<string name="tool_list_agents">List agents</string>
|
||
<string name="tool_team_named">Team: %1$s</string>
|
||
<string name="tool_create_team">Create Team</string>
|
||
<string name="tool_delete_team">Delete Team</string>
|
||
<string name="tool_todo_list">Todo list</string>
|
||
<string name="tool_plan">Plan</string>
|
||
<string name="tool_plan_proposal">Plan proposal</string>
|
||
<string name="chat_plan_implement">Implement plan</string>
|
||
<string name="chat_plan_continue">Continue planning</string>
|
||
<string name="tool_skill">Skill</string>
|
||
<string name="tool_skill_named">Skill: %1$s</string>
|
||
<string name="tool_reasoning">Reasoning</string>
|
||
<string name="tool_permission_request">Permission request</string>
|
||
<string name="tool_permission_named">Permission: %1$s</string>
|
||
<string name="tool_apply_changes">Apply changes</string>
|
||
<string name="tool_diff">Diff</string>
|
||
<string name="tool_task_log">%1$s log</string>
|
||
<string name="tool_inspecting_task_log">Inspecting task log</string>
|
||
<string name="tool_background_task">Background task</string>
|
||
<string name="tool_error">Error</string>
|
||
<string name="tool_run_shell">Run shell</string>
|
||
<string name="tool_search">Search</string>
|
||
<string name="tool_open_url">Open URL</string>
|
||
<string name="tool_query">Query</string>
|
||
<string name="tool_question">Question</string>
|
||
<string name="tool_questions">%1$d Questions</string>
|
||
<string name="tool_questions_more">%1$s (+%2$d more)</string>
|
||
<string name="tool_write_lines">%1$d lines</string>
|
||
<string name="tool_write_chars">%1$d chars</string>
|
||
<string name="tool_edits_count">%1$s (%2$d edits)</string>
|
||
|
||
<!-- Files browser + viewer (B-M4c) -->
|
||
<string name="files_back">Back</string>
|
||
<string name="files_title">Files</string>
|
||
<string name="files_refresh">Refresh</string>
|
||
<string name="files_tab_changes">Changes</string>
|
||
<string name="files_tab_browse">Browse</string>
|
||
<string name="files_tab_search">Search</string>
|
||
<string name="files_git_unavailable">Git status unavailable for this session</string>
|
||
<string name="files_detached_head">Detached HEAD</string>
|
||
<string name="files_staged_unstaged">%1$d staged · %2$d unstaged</string>
|
||
<string name="files_no_changes">No changes in the working tree</string>
|
||
<string name="files_staged_header">Staged (%1$d)</string>
|
||
<string name="files_unstaged_header">Unstaged (%1$d)</string>
|
||
<string name="files_project_root">Project root</string>
|
||
<string name="files_show_hidden">Show hidden files</string>
|
||
<string name="files_collapse">Collapse</string>
|
||
<string name="files_expand">Expand</string>
|
||
<string name="files_search_placeholder">Search files…</string>
|
||
<string name="files_search_hint">Type to search files in the session directory</string>
|
||
<string name="files_search_no_match">No files matched</string>
|
||
<string name="files_error_git_status">Git status unavailable</string>
|
||
<string name="files_error_unstaged_diff">Unstaged diff unavailable: %1$s</string>
|
||
<string name="files_error_staged_diff">Staged diff unavailable: %1$s</string>
|
||
<string name="files_error_unknown">unknown error</string>
|
||
<string name="files_error_list">Failed to list directory</string>
|
||
<string name="files_error_search">Failed to search files</string>
|
||
<string name="files_error_load_diff">Failed to load diff</string>
|
||
<string name="files_error_read_file">Failed to read file</string>
|
||
<string name="files_viewer_copied">Copied</string>
|
||
<string name="files_viewer_copy_path">Copy path</string>
|
||
<string name="files_viewer_diff">Diff</string>
|
||
<string name="files_viewer_file">File</string>
|
||
<string name="files_viewer_unstaged">Unstaged</string>
|
||
<string name="files_viewer_staged">Staged</string>
|
||
<string name="files_viewer_source">Source</string>
|
||
<string name="files_viewer_preview">Preview</string>
|
||
<string name="files_viewer_line">Line %1$d</string>
|
||
<string name="files_viewer_no_changes">No changes in this file</string>
|
||
<string name="files_viewer_empty">This file is empty</string>
|
||
<string name="files_viewer_binary">Binary file — no preview available</string>
|
||
<string name="files_viewer_image_unsupported">Preview not available for this image format</string>
|
||
|
||
<!-- Scratchlist workbench (B-M4d) -->
|
||
<string name="scratchlist_back">Back</string>
|
||
<string name="scratchlist_title">Scratchlist</string>
|
||
<string name="scratchlist_count_none">No notes</string>
|
||
<string name="scratchlist_count_one">1 note</string>
|
||
<string name="scratchlist_count_many">%1$d notes</string>
|
||
<string name="scratchlist_new_note">New note</string>
|
||
<string name="scratchlist_edit_note">Edit note</string>
|
||
<string name="scratchlist_to_composer">To composer</string>
|
||
<string name="scratchlist_attachment_only">Attachment only</string>
|
||
<string name="scratchlist_placeholder">Note, draft, parking-lot idea…</string>
|
||
<string name="scratchlist_add_photo">Add photo</string>
|
||
<string name="scratchlist_delete">Delete</string>
|
||
<string name="scratchlist_cancel">Cancel</string>
|
||
<string name="scratchlist_save">Save</string>
|
||
<string name="scratchlist_action_move_up">Move note up</string>
|
||
<string name="scratchlist_action_move_down">Move note down</string>
|
||
<string name="scratchlist_action_copy">Copy text to clipboard (not images)</string>
|
||
<string name="scratchlist_action_copied">Copied!</string>
|
||
<string name="scratchlist_confirm_delete">Delete this scratchlist entry? This cannot be undone.</string>
|
||
<string name="scratchlist_retry">Retry</string>
|
||
<string name="scratchlist_load_failed">Couldn’t load the scratchlist</string>
|
||
<string name="scratchlist_check_connection">Check the connection to your hub and try again.</string>
|
||
<string name="scratchlist_empty_title">No notes yet</string>
|
||
<string name="scratchlist_empty_hint">Park drafts from the composer, or tap + to jot a note for this session.</string>
|
||
<string name="scratchlist_notice_full_delete_first">Scratchlist is full (200 entries) — delete one first</string>
|
||
<string name="scratchlist_notice_full">Scratchlist is full (200 entries)</string>
|
||
<string name="scratchlist_notice_needs_content">A note needs text or an attachment — use Delete to remove it</string>
|
||
<string name="scratchlist_notice_save_failed">Couldn’t save the note — check the hub connection</string>
|
||
<string name="scratchlist_notice_delete_failed">Couldn’t delete the note — check the hub connection</string>
|
||
<string name="scratchlist_notice_attach_failed">Couldn’t attach the file — check the hub connection</string>
|
||
<string name="scratchlist_notice_remove_attachment_failed">Couldn’t remove the attachment — check the hub connection</string>
|
||
<string name="scratchlist_notice_too_large">That file is over the hub’s per-file size limit</string>
|
||
<string name="scratchlist_notice_upload_failed">Upload failed — check the hub connection</string>
|
||
<string name="scratchlist_reject_unreadable">Couldn’t read the selected file</string>
|
||
<string name="scratchlist_reject_image_too_large">Image is too large even after compression</string>
|
||
<string name="scratchlist_reject_max_attachments">A note can hold at most %1$d attachments</string>
|
||
<string name="scratchlist_reject_type">That file type isn’t allowed for scratchlist attachments</string>
|
||
<string name="scratchlist_reject_file_too_large">That file is over the %1$d MB limit</string>
|
||
<string name="scratchlist_reject_budget">This note’s attachment budget is used up</string>
|
||
|
||
<!-- Pairing errors (PairingViewModel semantic errors, B-M1d) -->
|
||
<string name="pairing_error_invalid_url">Enter a valid HTTPS hub URL, like https://hub.example.com.</string>
|
||
<string name="pairing_error_empty_token">Enter the access token shown by your hub.</string>
|
||
<string name="pairing_error_token_rejected">The hub rejected this access token. Tokens change when the hub rotates its CLI_API_TOKEN — grab a fresh QR code or token and try again.</string>
|
||
<string name="pairing_error_hub_gone">That hub is no longer paired. Pair it again below.</string>
|
||
<string name="pairing_error_unreachable">Could not reach %1$s. Check the address, your network, and that the hub is running.</string>
|
||
<string name="pairing_error_not_a_hub">%1$s answered, but not like a HAPI hub. Double-check the URL (it should be the hub’s own address, not the web app’s).</string>
|
||
<string name="pairing_error_protocol_update_app">This hub speaks protocol v%1$d but the app supports v%2$d. Update the app and try again.</string>
|
||
<string name="pairing_error_protocol_update_hub">This hub speaks protocol v%1$d but the app supports v%2$d. Update the hub and try again.</string>
|
||
<string name="pairing_error_auth_failed">Pairing failed (HTTP %1$d). Try again in a moment.</string>
|
||
<string name="pairing_notice_token_revoked">This device’s pairing was revoked — the hub’s access token changed. Pair again to continue.</string>
|
||
<string name="pairing_notice_retry_exhausted">The hub kept rejecting this device’s session. Pair again to continue.</string>
|
||
<string name="pairing_notice_missing_credentials">The stored credentials for this hub went missing. Pair again to continue.</string>
|
||
|
||
<!-- New session form notices (B-M3d) -->
|
||
<string name="new_session_error_worktree_missing">Worktree sessions require an existing repository directory.</string>
|
||
<string name="new_session_error_directory_missing">Directory does not exist. Creating the session will create it automatically.</string>
|
||
<string name="new_session_error_directory_missing_confirm">Directory does not exist. Tap Create again to create it automatically.</string>
|
||
<string name="new_session_error_create">Failed to create session</string>
|
||
<string name="new_session_error_codex_models">Failed to load Codex models</string>
|
||
<string name="new_session_error_models_detail">Failed to load models: %1$s</string>
|
||
<string name="new_session_error_worktree_name">Name needs at least one letter or digit</string>
|
||
<string name="new_session_error_directory_outside_workspace_roots">Directory must be inside one of this machine’s workspace roots.</string>
|
||
<string name="directory_browser_error">Failed to browse directories</string>
|
||
<string name="new_session_error_agent_availability">Failed to check installed Agents</string>
|
||
<string name="new_session_error_runner_upgrade_required">Upgrade and restart this machine’s HAPI runner before creating sessions.</string>
|
||
<string name="new_session_error_no_available_agents">No supported Agents are installed on this machine.</string>
|
||
<string name="new_session_error_selected_agent_unavailable">The selected Agent is not available on this machine.</string>
|
||
<string name="chat_back_to_latest">Back to latest ↓</string>
|
||
<string name="chat_history_retry">Couldn\'t load history. Tap to retry.</string>
|
||
<string name="chat_history_continue">Continue loading history</string>
|
||
<string name="chat_history_load">Load older messages</string>
|
||
<string name="chat_history_beginning">Beginning of conversation</string>
|
||
<string name="chat_copy_full_content">Copy full content</string>
|
||
<string name="chat_showing_parts">Showing %1$d of %2$d parts</string>
|
||
<string name="chat_load_more_content">Load more content</string>
|
||
<string name="tool_questions_answers">Questions & Answers</string>
|
||
<string name="tool_question_answers">Answers</string>
|
||
<string name="tool_custom_answer">Custom answer</string>
|
||
<string name="tool_answer_note">Note</string>
|
||
<string name="chat_view_full_message">View full message</string>
|
||
<string name="chat_full_message">Full message</string>
|
||
<string name="chat_previous_part">Previous part</string>
|
||
<string name="chat_next_part">Next part</string>
|
||
<string name="chat_part_number">Part %1$d</string>
|
||
<string name="chat_export_retry">Retry export</string>
|
||
<string name="chat_export_full_content">Export full text</string>
|
||
<string name="chat_content_copied">Copied</string>
|
||
<string name="chat_close_reader">Close reader</string>
|
||
<string name="chat_snapshot_notice">Read-only snapshot. This record is no longer in the current message window.</string>
|
||
<string name="chat_group_history_notice">Earlier calls are not loaded. Return to the conversation to load older history.</string>
|
||
<string name="chat_tool_details">Tool details</string>
|
||
<string name="chat_content_unavailable">This content is unavailable. Return to the conversation to load it again.</string>
|
||
<string name="chat_latest_tool">Latest tool</string>
|
||
<string name="chat_view_current_file">View current file</string>
|
||
<string name="chat_view_full_input">View full input</string>
|
||
<string name="chat_view_process">View process · %1$d steps</string>
|
||
<string name="chat_agent_process">Agent process</string>
|
||
<string name="chat_show_image">Show image</string>
|
||
<string name="media_displayed_image">Displayed image</string>
|
||
<string name="media_displayed_video">Displayed video</string>
|
||
<string name="media_displayed_audio">Displayed audio</string>
|
||
<string name="media_displayed_file">Displayed file</string>
|
||
<string name="media_displayed_header">%1$s: %2$s</string>
|
||
<string name="media_displayed_unavailable">%1$s is unavailable. %2$s</string>
|
||
<string name="media_load_video">Load video</string>
|
||
<string name="media_load_audio">Load audio</string>
|
||
<string name="media_prepare_download">Prepare download</string>
|
||
<string name="media_load_failed">Failed to load inline media</string>
|
||
<string name="media_playback_failed">Playback failed</string>
|
||
<string name="media_open">Open</string>
|
||
<string name="media_save">Save</string>
|
||
<string name="media_open_failed">No app can open this file.</string>
|
||
<string name="media_save_failed">Save failed.</string>
|
||
<string name="media_play">Play</string>
|
||
<string name="media_pause">Pause</string>
|
||
<string name="chat_reconnecting_retry">Reconnecting… Tap to retry</string>
|
||
<string name="sessions_filters">Filters</string>
|
||
<string name="sessions_filters_active">Filters applied</string>
|
||
<string name="sessions_filters_reset">Reset</string>
|
||
<string name="sessions_filters_done">Done</string>
|
||
<string name="sessions_filter_machines">Machines</string>
|
||
<string name="sessions_filter_dates">Activity dates</string>
|
||
<string name="sessions_filter_any_date">Any date</string>
|
||
<string name="sessions_filter_clear_dates">Clear date filter</string>
|
||
<string name="sessions_machine_fallback">Machine · %1$s</string>
|
||
<string name="sessions_time_filter_label">Filter sessions by last activity</string>
|
||
<string name="sessions_time_filter_apply">Apply</string>
|
||
<string name="sessions_time_filter_clear">Clear</string>
|
||
<string name="sessions_time_filter_summary">%1$s – %2$s</string>
|
||
<string name="sessions_time_filter_empty_title">No sessions in this date range</string>
|
||
<string name="sessions_time_filter_empty_hint">Adjust or clear the date filter to see more sessions.</string>
|
||
<string name="sessions_time_filter_recent_activity">Recent activity</string>
|
||
<string name="privacy_policy">Privacy Policy</string>
|
||
<string name="privacy_open_failed">No app can open this link.</string>
|
||
<!-- Incoming Android shares. -->
|
||
<string name="share_title">Share to session</string>
|
||
<string name="share_choose_session">Choose a session</string>
|
||
<string name="share_search_hint">Search sessions</string>
|
||
<string name="share_copying">Preparing shared file…</string>
|
||
<string name="share_importing">Adding shared content…</string>
|
||
<string name="share_unreadable">Cannot read this file. Retry or remove it.</string>
|
||
<string name="share_too_large">File exceeds the attachment size limit.</string>
|
||
<string name="share_interrupted">Preparation was interrupted. Retry or remove this file.</string>
|
||
<string name="share_retry">Retry</string>
|
||
<string name="share_remove">Remove</string>
|
||
<string name="share_cancel">Cancel</string>
|
||
<string name="share_receive_failed">Cannot receive this share. Please share the content again.</string>
|
||
<string name="share_restore_title">Restore session?</string>
|
||
<string name="share_restore_message">This session is stopped. Restore it before adding the shared content?</string>
|
||
<string name="share_restore_confirm">Restore and add</string>
|
||
<string name="share_restore_label">Stopped · restore before adding</string>
|
||
<string name="share_target_failed">Cannot open this session. Check the connection and try again.</string>
|
||
<string name="share_refresh">Refresh sessions</string>
|
||
<string name="share_no_sessions">No matching sessions</string>
|
||
<string name="share_offline">Cannot refresh sessions. Check the connection or switch hubs.</string>
|
||
<string name="share_replace_title">Another share received</string>
|
||
<string name="share_replace_message">There is already shared content waiting to be added. Keep it and discard the new share, or replace it with the new share?</string>
|
||
<string name="share_keep_current">Keep current</string>
|
||
<string name="share_replace_current">Use new share</string>
|
||
<string name="share_error_title">Share unavailable</string>
|
||
<string name="share_ok">OK</string>
|
||
<string name="share_pair_first">Pair a hub to choose a session for the shared content.</string>
|
||
<string name="chat_notice_read_state_failed">Couldn’t save read status</string>
|
||
|
||
<!-- Global connection + runner version-skew banners (Home chrome). -->
|
||
<string name="connection_reconnecting">Reconnecting…</string>
|
||
<string name="connection_syncing">Syncing…</string>
|
||
<string name="connection_reason_heartbeat_timeout">heartbeat timeout</string>
|
||
<string name="connection_reason_visibility_recovery">resuming after background</string>
|
||
<string name="connection_reason_connect_timeout">connect timeout</string>
|
||
<string name="connection_reason_transport_error">stream error</string>
|
||
<string name="connection_reason_closed">stream closed</string>
|
||
<string name="connection_reason_http_code">HTTP %1$d</string>
|
||
<string name="runner_skew_summary_title">%1$d runner(s) out of date</string>
|
||
<string name="runner_skew_summary_body">Upgrade the HAPI CLI on each host below, then restart that runner. Minimize or snooze this banner to reach sessions underneath.</string>
|
||
<string name="runner_skew_minimized">%1$d outdated runner(s): %2$s — tap to expand</string>
|
||
<string name="runner_skew_minimize">Minimize</string>
|
||
<string name="runner_skew_dismiss_temp">Snooze 1h</string>
|
||
<string name="runner_skew_restart">Restart runner</string>
|
||
<string name="runner_skew_restart_unavailable">Upgrade CLI first</string>
|
||
<string name="runner_skew_restarting">Restarting…</string>
|
||
<string name="runner_skew_binary_updated_hint">(newer CLI on disk — runner should self-restart soon)</string>
|
||
<string name="runner_skew_upgrade_cli_first">(no newer CLI on disk yet — install/upgrade on that host)</string>
|
||
<string name="runner_skew_restart_failed">Failed to restart runner</string>
|
||
</resources>
|