fix(cli): human-readable API error messages

ApiError previously displayed raw JSON like:
  API error 403: {"code":403,"msg":"Access denied..."}

Now extracts the msg field from the API response body and displays:
  Access denied to skill: find-skills
  Run `skillhub login` to authenticate.

Changes:
- Add extractHumanMessage() to pull msg/message/error from response
- ApiError.message now shows human text instead of raw JSON
- 401/403 responses append login hint
- whoami: remove redundant 'Not authenticated:' prefix
This commit is contained in:
chenbaowang 2026-04-21 10:19:38 +08:00
parent f5caed955e
commit 8815c1596c
2 changed files with 22 additions and 2 deletions

View file

@ -23,7 +23,7 @@ export function registerWhoami(program: Command) {
console.log(`Display Name: ${resp.user.displayName}`);
}
} catch (e: any) {
error(`Not authenticated: ${e.message}`);
error(e.message);
process.exit(1);
}
});

View file

@ -121,11 +121,31 @@ export class ApiClient {
}
}
function extractHumanMessage(body: unknown): string | null {
if (typeof body !== "object" || body === null) return null;
const b = body as Record<string, unknown>;
// Native API: { code, msg, data } — "msg" is authoritative
if (typeof b.msg === "string" && b.msg.length > 0) return b.msg;
if (typeof b.message === "string" && b.message.length > 0) return b.message;
if (typeof b.error === "string" && b.error.length > 0) return b.error;
return null;
}
export class ApiError extends Error {
constructor(
public statusCode: number,
public body: unknown,
) {
super(`API error ${statusCode}: ${JSON.stringify(body)}`);
const msg = extractHumanMessage(body);
let detail = msg ?? `HTTP ${statusCode}`;
if (statusCode === 401 || statusCode === 403) {
detail += "\nRun `skillhub login` to authenticate.";
}
super(detail);
}
}