feat(pet): cleared alerts stay cleared, contextual bubbles, i18n, moments, chat window
- Fix: an errored session alerted on every update, and Clear alerts only dropped it in memory, so its next update (or a reload) brought the alert straight back. An error now alerts on the transition into error only; cleared sessions are remembered (agenthub.pet.dismissedErrors) and stay quiet until they recover and fail anew. - Quips, greetings, notifications and Ask answers move to i18n (EN/VI); Ask understands Vietnamese keywords and names the sessions it counts. - The pet goes by the worn pet's name; click it in the panel to rename (agenthub.pet.names, synced to the account). - Bubbles name the session they are about, with an Open button (never a resume); a burst of the same event coalesces into one count. - Moments: a new session waves, a finish hops, a subagent peeks, a wait taps, an error flinches — on Sagi, Codex sprites and still images. Idle fidgets, a once-per-session greeting, a "Needs you" list, an amber waiting dot. - Pat (heart button, Ask, or stroking the pet) reacts on the pet itself, so it shows while the panel or chat is open. - Panel drops Run Claude / Activity / Sessions / Errored. - Ask hands off to a chat window (PetChat) on the default AI tool (Claude/Codex): transcript as bubbles, follow-ups and CLI menus through an off-screen attached terminal; no new server route. Verified on HEAD + this diff in a clean worktree: tsc -b, the full client suite (1334/1335; the one failure, ConversationView.follow, is flaky under load and passes 3/3 alone) and server me-prefs.test.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,29 +37,199 @@
|
||||
"chooseDesc": "Featured pets come from codex-pets.net and are downloaded into this install the first time you pick one. Your choice and size are saved to your account.",
|
||||
"uploadHint": "An image (PNG, JPEG, GIF, WebP — no SVG) is shown still; a .codex-pet.zip (pet.json + a 1536×1872 spritesheet.webp) is animated by mood.",
|
||||
"panel": {
|
||||
"label": "Sagi companion",
|
||||
"label": "{{name}} companion",
|
||||
"live": "Live",
|
||||
"offline": "Offline",
|
||||
"close": "Close Sagi",
|
||||
"close": "Close {{name}}",
|
||||
"statLive": "live",
|
||||
"statWaiting": "waiting",
|
||||
"statErrored": "errored",
|
||||
"runClaude": "Run Claude",
|
||||
"activity": "Activity",
|
||||
"sessions": "Sessions",
|
||||
"errored": "Errored",
|
||||
"mute": "Mute",
|
||||
"unmute": "Unmute",
|
||||
"clearAlerts": "Clear alerts",
|
||||
"askPlaceholder": "Ask Sagi… (e.g. any errors?)",
|
||||
"ask": "Ask Sagi",
|
||||
"send": "Send"
|
||||
"askPlaceholder": "Ask {{name}}… (e.g. any errors?)",
|
||||
"ask": "Ask {{name}}",
|
||||
"send": "Send",
|
||||
"rename": "Click to rename {{name}}",
|
||||
"renameLabel": "Pet name",
|
||||
"renameHint": "Enter to save · empty = default name",
|
||||
"pat": "Pat {{name}}",
|
||||
"attention": "Needs you",
|
||||
"attentionError": "errored",
|
||||
"attentionWaiting": "waiting on you",
|
||||
"attentionMore": "+{{count}} more in Sessions",
|
||||
"chat": "Chat with {{name}}"
|
||||
},
|
||||
"bubbleDismiss": "Dismiss",
|
||||
"open": "Open Sagi companion",
|
||||
"closeAvatar": "Close Sagi",
|
||||
"avatarTitle": "Sagi — Ctrl/⌘+B · drag or arrow keys to move · right-click for pets",
|
||||
"startFailed": "Couldn't start that session: {{error}}"
|
||||
"open": "Open {{name}} companion",
|
||||
"closeAvatar": "Close {{name}}",
|
||||
"avatarTitle": "{{name}} — Ctrl/⌘+B · drag or arrow keys to move · stroke to pat · right-click for pets",
|
||||
"startFailed": "Couldn't start that session: {{error}}",
|
||||
"bubbleOpen": "Open",
|
||||
"bubbleMore": "{{list}} +{{count}} more",
|
||||
"notify": {
|
||||
"session_done_one": "{{count}} session finished ✨",
|
||||
"session_done_other": "{{count}} sessions finished ✨",
|
||||
"session_start_one": "{{count}} new session started 👀",
|
||||
"session_start_other": "{{count}} new sessions started 👀",
|
||||
"subagent_spawn_one": "{{count}} subagent joined in 🤝",
|
||||
"subagent_spawn_other": "{{count}} subagents joined in 🤝",
|
||||
"waiting_one": "{{count}} session is waiting on you ⏳",
|
||||
"waiting_other": "{{count}} sessions are waiting on you ⏳",
|
||||
"error_one": "{{count}} error just popped up 😿",
|
||||
"error_other": "{{count}} errors just popped up 😿",
|
||||
"run_done_one": "{{count}} run finished 🐾",
|
||||
"run_done_other": "{{count}} runs finished 🐾"
|
||||
},
|
||||
"greet": {
|
||||
"morning": [
|
||||
"good morning! ☀️",
|
||||
"morning! coffee first? ☕",
|
||||
"rise and shine 🌤️"
|
||||
],
|
||||
"afternoon": [
|
||||
"good afternoon! 🐾",
|
||||
"hey, welcome back 😺",
|
||||
"afternoon! ready when you are ✨"
|
||||
],
|
||||
"evening": [
|
||||
"good evening! 🌆",
|
||||
"evening shift? I'm in 😼",
|
||||
"hey there, night owl-to-be 🌙"
|
||||
],
|
||||
"night": [
|
||||
"burning the midnight oil? 🌙",
|
||||
"late one, huh? I'll keep watch 🦉",
|
||||
"still up? don't forget to rest 💤"
|
||||
],
|
||||
"summary_one": "{{count}} session live",
|
||||
"summary_other": "{{count}} sessions live",
|
||||
"summaryWaiting": "{{count}} waiting on you",
|
||||
"summaryErrors": "{{count}} errored"
|
||||
},
|
||||
"pat": [
|
||||
"purr… 💜",
|
||||
"hehe, that tickles 😸",
|
||||
"*happy wiggle* ✨",
|
||||
"more pats please 🐾",
|
||||
"best human 😻"
|
||||
],
|
||||
"intent": {
|
||||
"empty": "ask me about your sessions - what's running, any errors, or a quick status.",
|
||||
"help": "I'm {{name}} - I watch your sessions. Try \"what's running\", \"any errors\", \"what's waiting\" or \"status\". Anything else, I'll hand to Claude.",
|
||||
"whoami": "I'm {{name}}, your session-watching buddy 🐾 Right-click me to change my look, or click my name in the panel to rename me.",
|
||||
"hello": "hi there! 😺 {{summary}}.",
|
||||
"thanks": [
|
||||
"anytime! 💜",
|
||||
"happy to help 😸",
|
||||
"you got it 🐾"
|
||||
],
|
||||
"errors_one": "{{count}} session errored{{list}} - open the panel to jump to it.",
|
||||
"errors_other": "{{count}} sessions errored{{list}} - open the panel to jump to them.",
|
||||
"errorsNone": "no errors - all clean 🐾",
|
||||
"waiting_one": "{{count}} session waiting on you{{list}} 👀",
|
||||
"waiting_other": "{{count}} sessions waiting on you{{list}} 👀",
|
||||
"waitingNone": "nothing's waiting on you right now 🐾",
|
||||
"live_one": "{{count}} session live right now 🐾{{tail}}",
|
||||
"live_other": "{{count}} sessions live right now 🐾{{tail}}",
|
||||
"liveTail": " ({{count}} waiting on you 👀)",
|
||||
"liveNone": "nothing's running right now - all quiet.",
|
||||
"status": "{{live}} live · {{waiting}} waiting · {{errors}} errored · {{conn}}.",
|
||||
"connected": "connected",
|
||||
"offline": "offline"
|
||||
},
|
||||
"quips": {
|
||||
"session_done": [
|
||||
"a session just wrapped up! 🐾",
|
||||
"a session finished - nice work! ✨",
|
||||
"that session's all done 😺",
|
||||
"clean finish on that one 💜"
|
||||
],
|
||||
"session_start": [
|
||||
"a new session started! 👀",
|
||||
"a fresh session just landed 🐾",
|
||||
"ooh, a new session to watch 😻",
|
||||
"something new is cooking 🍲"
|
||||
],
|
||||
"subagent_spawn": [
|
||||
"a subagent just spawned! 🐾",
|
||||
"a little helper joined in 🤝",
|
||||
"a subagent's on the job 🚀",
|
||||
"reinforcements - new subagent! 😺"
|
||||
],
|
||||
"waiting": [
|
||||
"a session needs your input 👀",
|
||||
"a session is waiting on you ⏳",
|
||||
"a session paused for your reply 💬",
|
||||
"your turn - a session's waiting 🐾"
|
||||
],
|
||||
"error": [
|
||||
"uh oh, a session hit an error 😿",
|
||||
"something broke - wanna peek? 🙀",
|
||||
"a hook tripped on something ⚠️",
|
||||
"hiss… an error popped up 💢"
|
||||
],
|
||||
"run_done": [
|
||||
"your run just finished! 🐾",
|
||||
"the run's all wrapped up ✨",
|
||||
"run complete - that's a wrap 😸",
|
||||
"all done with that run 💜"
|
||||
],
|
||||
"disconnected": [
|
||||
"lost the connection… 😴",
|
||||
"can't reach the server 📡",
|
||||
"no signal - taking a nap 💤"
|
||||
],
|
||||
"worried": [
|
||||
"that didn't look right 😟",
|
||||
"keeping an eye out 👀",
|
||||
"hmm, something's off 🫣"
|
||||
],
|
||||
"stuck": [
|
||||
"a session's been quiet a while… 🤔",
|
||||
"is something stuck? ⏳",
|
||||
"still chewing on it… 😾"
|
||||
],
|
||||
"happy": [
|
||||
"great run! 😻",
|
||||
"love a tidy finish ✨",
|
||||
"purrfect 💜"
|
||||
],
|
||||
"thinking": [
|
||||
"hmm, let me look… 🤔",
|
||||
"sniffing around… 🐾",
|
||||
"one sec, checking 🔍"
|
||||
],
|
||||
"watching": [
|
||||
"on the prowl 👀",
|
||||
"watching your sessions 😼",
|
||||
"eyes peeled 🐾"
|
||||
],
|
||||
"sleeping": [
|
||||
"zzz… 💤",
|
||||
"wake me if something happens 😴",
|
||||
"curled up, all calm 🐈"
|
||||
],
|
||||
"idle": [
|
||||
"all quiet 😺",
|
||||
"ready when you are 🐾",
|
||||
"just vibing ✨"
|
||||
]
|
||||
},
|
||||
"chat": {
|
||||
"label": "Chat with {{name}}",
|
||||
"back": "Back",
|
||||
"close": "Close {{name}}",
|
||||
"new": "New chat",
|
||||
"openWorkspace": "Open in workspace",
|
||||
"typing": "typing…",
|
||||
"placeholder": "Ask {{name}} anything…",
|
||||
"emptyTitle": "Hi! I'm {{name}} 🐾",
|
||||
"emptyHint": "Ask me anything — I'll get {{tool}} to answer right here.",
|
||||
"starting": "Starting {{tool}}…",
|
||||
"notStarted": "Waiting for the session to start — if it asks something, open it in the workspace.",
|
||||
"notSent": "Couldn't reach the session's terminal — try again, or open it in the workspace."
|
||||
}
|
||||
},
|
||||
"pricing": {
|
||||
"vendor": {
|
||||
|
||||
@@ -37,29 +37,199 @@
|
||||
"chooseDesc": "Pet nổi bật lấy từ codex-pets.net và được tải về máy ở lần đầu bạn chọn. Lựa chọn và kích thước được lưu vào tài khoản của bạn.",
|
||||
"uploadHint": "Ảnh (PNG, JPEG, GIF, WebP — không nhận SVG) hiển thị tĩnh; file .codex-pet.zip (pet.json + spritesheet.webp 1536×1872) chuyển động theo tâm trạng.",
|
||||
"panel": {
|
||||
"label": "Trợ lý Sagi",
|
||||
"label": "Trợ lý {{name}}",
|
||||
"live": "Trực tuyến",
|
||||
"offline": "Ngoại tuyến",
|
||||
"close": "Đóng Sagi",
|
||||
"close": "Đóng {{name}}",
|
||||
"statLive": "đang chạy",
|
||||
"statWaiting": "đang chờ",
|
||||
"statErrored": "lỗi",
|
||||
"runClaude": "Chạy Claude",
|
||||
"activity": "Hoạt động",
|
||||
"sessions": "Phiên",
|
||||
"errored": "Phiên lỗi",
|
||||
"mute": "Tắt tiếng",
|
||||
"unmute": "Bật tiếng",
|
||||
"clearAlerts": "Xoá cảnh báo",
|
||||
"askPlaceholder": "Hỏi Sagi… (vd: có lỗi nào không?)",
|
||||
"ask": "Hỏi Sagi",
|
||||
"send": "Gửi"
|
||||
"askPlaceholder": "Hỏi {{name}}… (vd: có lỗi nào không?)",
|
||||
"ask": "Hỏi {{name}}",
|
||||
"send": "Gửi",
|
||||
"rename": "Bấm để đổi tên {{name}}",
|
||||
"renameLabel": "Tên pet",
|
||||
"renameHint": "Enter để lưu · để trống = tên mặc định",
|
||||
"pat": "Xoa đầu {{name}}",
|
||||
"attention": "Cần bạn xem",
|
||||
"attentionError": "bị lỗi",
|
||||
"attentionWaiting": "đang chờ bạn",
|
||||
"attentionMore": "+{{count}} phiên khác trong Phiên",
|
||||
"chat": "Trò chuyện với {{name}}"
|
||||
},
|
||||
"bubbleDismiss": "Đóng",
|
||||
"open": "Mở trợ lý Sagi",
|
||||
"closeAvatar": "Đóng Sagi",
|
||||
"avatarTitle": "Sagi — Ctrl/⌘+B · kéo hoặc dùng phím mũi tên để di chuyển · chuột phải để chọn pet",
|
||||
"startFailed": "Không khởi động được phiên: {{error}}"
|
||||
"open": "Mở trợ lý {{name}}",
|
||||
"closeAvatar": "Đóng {{name}}",
|
||||
"avatarTitle": "{{name}} — Ctrl/⌘+B · kéo hoặc dùng phím mũi tên để di chuyển · vuốt qua lại để xoa đầu · chuột phải để chọn pet",
|
||||
"startFailed": "Không khởi động được phiên: {{error}}",
|
||||
"bubbleOpen": "Mở",
|
||||
"bubbleMore": "{{list}} và {{count}} phiên khác",
|
||||
"notify": {
|
||||
"session_done_one": "{{count}} phiên vừa xong ✨",
|
||||
"session_done_other": "{{count}} phiên vừa xong ✨",
|
||||
"session_start_one": "{{count}} phiên mới vừa bắt đầu 👀",
|
||||
"session_start_other": "{{count}} phiên mới vừa bắt đầu 👀",
|
||||
"subagent_spawn_one": "{{count}} subagent vừa vào việc 🤝",
|
||||
"subagent_spawn_other": "{{count}} subagent vừa vào việc 🤝",
|
||||
"waiting_one": "{{count}} phiên đang chờ bạn ⏳",
|
||||
"waiting_other": "{{count}} phiên đang chờ bạn ⏳",
|
||||
"error_one": "Vừa có {{count}} lỗi 😿",
|
||||
"error_other": "Vừa có {{count}} lỗi 😿",
|
||||
"run_done_one": "{{count}} lượt chạy vừa xong 🐾",
|
||||
"run_done_other": "{{count}} lượt chạy vừa xong 🐾"
|
||||
},
|
||||
"greet": {
|
||||
"morning": [
|
||||
"chào buổi sáng! ☀️",
|
||||
"sáng rồi! cà phê chưa? ☕",
|
||||
"ngày mới tốt lành nha 🌤️"
|
||||
],
|
||||
"afternoon": [
|
||||
"chào buổi chiều! 🐾",
|
||||
"bạn quay lại rồi 😺",
|
||||
"chiều nay làm gì đây? ✨"
|
||||
],
|
||||
"evening": [
|
||||
"chào buổi tối! 🌆",
|
||||
"ca tối hả? có mình đây 😼",
|
||||
"tối rồi, cố lên nhé 🌙"
|
||||
],
|
||||
"night": [
|
||||
"khuya rồi mà vẫn làm à? 🌙",
|
||||
"để mình canh giúp cho 🦉",
|
||||
"nhớ nghỉ ngơi nha 💤"
|
||||
],
|
||||
"summary_one": "{{count}} phiên đang chạy",
|
||||
"summary_other": "{{count}} phiên đang chạy",
|
||||
"summaryWaiting": "{{count}} phiên chờ bạn",
|
||||
"summaryErrors": "{{count}} phiên lỗi"
|
||||
},
|
||||
"pat": [
|
||||
"grừ grừ… 💜",
|
||||
"hihi, nhột quá 😸",
|
||||
"*vẫy đuôi* ✨",
|
||||
"xoa nữa đi mà 🐾",
|
||||
"chủ nhân tuyệt nhất 😻"
|
||||
],
|
||||
"intent": {
|
||||
"empty": "hỏi mình về các phiên nhé - đang chạy gì, có lỗi không, hay tình hình chung.",
|
||||
"help": "Mình là {{name}} - mình canh các phiên của bạn. Thử hỏi \"đang chạy gì\", \"có lỗi không\", \"cái gì đang chờ\" hoặc \"tình hình\". Câu khác mình sẽ chuyển cho Claude.",
|
||||
"whoami": "Mình là {{name}}, bạn đồng hành canh phiên của bạn 🐾 Chuột phải vào mình để đổi ngoại hình, hoặc bấm vào tên trong bảng để đặt tên mới.",
|
||||
"hello": "chào bạn! 😺 {{summary}}.",
|
||||
"thanks": [
|
||||
"có gì đâu! 💜",
|
||||
"rất vui được giúp 😸",
|
||||
"chuyện nhỏ 🐾"
|
||||
],
|
||||
"errors_one": "{{count}} phiên bị lỗi{{list}} - mở bảng để xem nhé.",
|
||||
"errors_other": "{{count}} phiên bị lỗi{{list}} - mở bảng để xem nhé.",
|
||||
"errorsNone": "không có lỗi nào - sạch sẽ 🐾",
|
||||
"waiting_one": "{{count}} phiên đang chờ bạn{{list}} 👀",
|
||||
"waiting_other": "{{count}} phiên đang chờ bạn{{list}} 👀",
|
||||
"waitingNone": "hiện không có gì chờ bạn cả 🐾",
|
||||
"live_one": "{{count}} phiên đang chạy 🐾{{tail}}",
|
||||
"live_other": "{{count}} phiên đang chạy 🐾{{tail}}",
|
||||
"liveTail": " ({{count}} phiên chờ bạn 👀)",
|
||||
"liveNone": "hiện không có gì đang chạy - yên ắng.",
|
||||
"status": "{{live}} đang chạy · {{waiting}} đang chờ · {{errors}} lỗi · {{conn}}.",
|
||||
"connected": "đã kết nối",
|
||||
"offline": "mất kết nối"
|
||||
},
|
||||
"quips": {
|
||||
"session_done": [
|
||||
"một phiên vừa xong! 🐾",
|
||||
"xong một phiên rồi - giỏi lắm! ✨",
|
||||
"phiên đó xong xuôi rồi 😺",
|
||||
"kết thúc gọn gàng 💜"
|
||||
],
|
||||
"session_start": [
|
||||
"có phiên mới bắt đầu! 👀",
|
||||
"một phiên mới vừa tới 🐾",
|
||||
"ồ, có phiên mới để canh 😻",
|
||||
"có gì đó đang được nấu 🍲"
|
||||
],
|
||||
"subagent_spawn": [
|
||||
"một subagent vừa xuất hiện! 🐾",
|
||||
"có trợ thủ nhỏ vào cuộc 🤝",
|
||||
"subagent đã nhận việc 🚀",
|
||||
"viện binh tới - subagent mới! 😺"
|
||||
],
|
||||
"waiting": [
|
||||
"một phiên cần bạn trả lời 👀",
|
||||
"có phiên đang chờ bạn ⏳",
|
||||
"một phiên tạm dừng chờ bạn 💬",
|
||||
"tới lượt bạn - có phiên đang chờ 🐾"
|
||||
],
|
||||
"error": [
|
||||
"ối, một phiên bị lỗi 😿",
|
||||
"có gì đó hỏng rồi - xem thử không? 🙀",
|
||||
"một hook vừa vấp phải lỗi ⚠️",
|
||||
"khè… lỗi xuất hiện 💢"
|
||||
],
|
||||
"run_done": [
|
||||
"lượt chạy của bạn xong rồi! 🐾",
|
||||
"lượt chạy đã hoàn tất ✨",
|
||||
"chạy xong - hết phim 😸",
|
||||
"xong lượt chạy đó rồi 💜"
|
||||
],
|
||||
"disconnected": [
|
||||
"mất kết nối rồi… 😴",
|
||||
"không gọi được máy chủ 📡",
|
||||
"mất sóng - đi ngủ chút 💤"
|
||||
],
|
||||
"worried": [
|
||||
"có vẻ không ổn 😟",
|
||||
"mình đang để mắt đây 👀",
|
||||
"hừm, có gì đó lạ lạ 🫣"
|
||||
],
|
||||
"stuck": [
|
||||
"một phiên im lặng lâu rồi… 🤔",
|
||||
"có gì bị kẹt không? ⏳",
|
||||
"vẫn đang nhai… 😾"
|
||||
],
|
||||
"happy": [
|
||||
"tuyệt vời! 😻",
|
||||
"kết thúc gọn ghê ✨",
|
||||
"hoàn hảo 💜"
|
||||
],
|
||||
"thinking": [
|
||||
"để mình xem… 🤔",
|
||||
"đang đánh hơi… 🐾",
|
||||
"chờ chút, đang kiểm tra 🔍"
|
||||
],
|
||||
"watching": [
|
||||
"đang tuần tra 👀",
|
||||
"đang canh các phiên của bạn 😼",
|
||||
"mắt mở to 🐾"
|
||||
],
|
||||
"sleeping": [
|
||||
"zzz… 💤",
|
||||
"có gì thì gọi mình dậy nhé 😴",
|
||||
"cuộn tròn, mọi thứ yên ổn 🐈"
|
||||
],
|
||||
"idle": [
|
||||
"yên ắng quá 😺",
|
||||
"sẵn sàng khi bạn cần 🐾",
|
||||
"chill thôi ✨"
|
||||
]
|
||||
},
|
||||
"chat": {
|
||||
"label": "Trò chuyện với {{name}}",
|
||||
"back": "Quay lại",
|
||||
"close": "Đóng {{name}}",
|
||||
"new": "Cuộc trò chuyện mới",
|
||||
"openWorkspace": "Mở trong workspace",
|
||||
"typing": "đang trả lời…",
|
||||
"placeholder": "Hỏi {{name}} bất cứ điều gì…",
|
||||
"emptyTitle": "Chào bạn! Mình là {{name}} 🐾",
|
||||
"emptyHint": "Hỏi gì cũng được — mình sẽ nhờ {{tool}} trả lời ngay tại đây.",
|
||||
"starting": "Đang khởi động {{tool}}…",
|
||||
"notStarted": "Đang chờ phiên khởi động — nếu nó hỏi gì, hãy mở trong workspace.",
|
||||
"notSent": "Không gửi được tới terminal của phiên — thử lại, hoặc mở trong workspace."
|
||||
}
|
||||
},
|
||||
"pricing": {
|
||||
"vendor": {
|
||||
|
||||
Reference in New Issue
Block a user