fix: v2.5.9 — Vietnamese in the terminal on macOS, every slash command, the right Claude account
Issue #62: a tmux client whose LC_ALL/LC_CTYPE/LANG names no UTF-8 prints `_` for every non-ASCII character, and a macOS LaunchAgent starts the dashboard with no locale at all — Vietnamese text and Claude Code's logo came out as underscores in every browser terminal. - shell-path.js: ensureUtf8Locale() defaults LC_CTYPE (en_US.UTF-8 on macOS, C.UTF-8 elsewhere) at start, before any tmux call; an explicit LC_ALL and Windows are left alone - RunSetup.tsx: the `/` list now offers Claude Code's bundled skills (/code-review, /security-review, /simplify, /loop…) and newer built-ins, and every enabled plugin's commands and skills as /<plugin>:<name> - Claude login decided by the TOKEN's owner (GET /api/oauth/profile, cached per token), not by .claude.json: a running session can leave the credentials store holding one account's token under another account's name. The Profiles modal, its Check quota and the status-bar quota now show the account requests are really billed to and warn on the mismatch; a switch saves the outgoing token into its OWNER's profile (credentials only) instead of overwriting the profile .claude.json names; saving a profile while they disagree is refused (EMISMATCH); a saved profile holding another account's token reports EWRONGACCOUNT instead of that account's usage - Running Claude Code sessions follow a switch on their own (they re-read the credentials store when it changes), so the "close your sessions first" warning is gone
This commit is contained in:
@@ -531,6 +531,7 @@ const PROFILE_ERR_TO_STATUS = {
|
||||
ENOAUTH: 409,
|
||||
EDUPLICATE: 409,
|
||||
ELABELTAKEN: 409,
|
||||
EMISMATCH: 409,
|
||||
};
|
||||
|
||||
function profileError(res, e) {
|
||||
@@ -538,17 +539,21 @@ function profileError(res, e) {
|
||||
return res.status(status).json({ error: { code: e.code || "EINTERNAL", message: e.message } });
|
||||
}
|
||||
|
||||
router.get("/profiles", (_req, res) => {
|
||||
// The live token's owner (asked of Anthropic, cached per token) decides who is
|
||||
// logged in — `.claude.json` can name another account. Null offline: then the
|
||||
// config is all there is, as before.
|
||||
router.get("/profiles", async (_req, res) => {
|
||||
try {
|
||||
res.json(ccProfiles.listProfiles());
|
||||
res.json(ccProfiles.listProfiles({ owner: await ccUsage.liveOwner() }));
|
||||
} catch (e) {
|
||||
return profileError(res, e);
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/profiles", (req, res) => {
|
||||
router.post("/profiles", async (req, res) => {
|
||||
try {
|
||||
const result = ccProfiles.saveProfile((req.body || {}).name);
|
||||
const owner = await ccUsage.liveOwner();
|
||||
const result = ccProfiles.saveProfile((req.body || {}).name, { owner });
|
||||
emitChanged({ action: "save", type: "profile", name: result.name, project: null });
|
||||
res.json(result);
|
||||
} catch (e) {
|
||||
@@ -568,9 +573,10 @@ router.patch("/profiles", (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/profiles/activate", (req, res) => {
|
||||
router.post("/profiles/activate", async (req, res) => {
|
||||
try {
|
||||
const result = ccProfiles.activateProfile((req.body || {}).name);
|
||||
const owner = await ccUsage.liveOwner();
|
||||
const result = ccProfiles.activateProfile((req.body || {}).name, { owner });
|
||||
emitChanged({ action: "activate", type: "profile", name: result.name, project: null });
|
||||
res.json(result);
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user