* feat(cli): persist + show friendly user identity; preserve unknown credential fields
The `~/.heygen/credentials` file is SHARED with the Go `heygen` CLI. This
is the hyperframes-side mirror of heygen-cli#197, which adds an optional
`user` block to that file. Two CLIs writing one file must round-trip each
other's data without loss.
Load-bearing change: the credentials reader/writer now PRESERVES unknown
fields on round-trip. Previously readStore/writeStore stripped any key
this CLI didn't model, so writing the file back would silently drop the
`user` block heygen-cli wrote (and any future key). Unrecognized top-level
keys, and unknown keys inside `oauth` / `user`, are captured on a hidden
symbol slot and re-emitted verbatim. Known fields stay strictly validated.
Also mirrors heygen-cli#197's friendly-display feature:
- New optional `user` block schema (email/first_name/last_name/username),
all omitempty; legacy files without it parse fine.
- After login (OAuth + api-key paths) probe /v3/users/me, persist the
block, and show a friendly name (email > "first last" > username).
Probe failure is non-fatal (login still succeeds); a stale block is
cleared on probe failure so a wrong account can't surface.
- `auth status` surfaces the persisted block (persisted_user in JSON,
a cached Account row in human output) for file-sourced credentials;
env-sourced credentials skip it (the on-disk block may belong to a
different key).
- Fixed the OAuth write path to carry the user block + unknown keys
across a fresh login / refresh (it previously rebuilt a minimal record).
Tests: preserve-unknown-fields round-trip (top-level, oauth, user), the
exact cross-CLI `user`-block scenario, schema round-trip + omitempty,
backwards-compat with legacy files, login persistence + graceful probe
failure + stale-clear, and the `auth status` surface. Full CLI suite
(1009 tests) green; oxlint + oxfmt + tsc clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): preserve unknown credential data in cleanup/rollback paths
Addresses Magi's REQUEST_CHANGES on #1741. The credentials reader/writer
already round-trips unknown/foreign keys (the cross-CLI forward-compat
contract), but three destructive paths still deleted the whole file when
no known api_key/oauth survived — even when the hidden Symbol-keyed
unknown-field bag held a future credential another CLI owns. That clobbers
exactly the data this PR preserves.
- Add `hasPreservedUnknownData(record)` to store.ts (checks the top-level
unknown bag + the oauth/user sub-object bags) and export it via the
barrel.
- `clearOAuth`, `clearUserInfo`, and the failed `auth login --api-key`
rollback now write the credential-less remnant (carrying the unknown
bag) instead of deleting the file when unknown/foreign data survives.
They still delete when nothing worth preserving remains.
- Regression tests: rollback path + both cleanup paths (clearOAuth,
clearUserInfo) preserve a foreign top-level key; `hasPreservedUnknownData`
unit tests at all three levels.
Also addresses the review's minor items:
- Add a refresh-path round-trip test (`refreshTokens`) proving an unknown
key inside the oauth sub-object survives a no-rotation refresh — the
most-frequent write path, previously only implicitly covered.
- Clarify the `userDisplayName` / `combineName` docstrings: precedence is
`email > "first last" > first-only > last-only > username`.
- Replace the stale `expires_at` example date in store.ts with
`<ISO-8601 UTC>`.
Full CLI suite green (1020 tests); tsc, oxlint, oxfmt --check all clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>