Skip to content

Make accounts org-aware: dedupe by account + organization - #23

Closed
grosmar wants to merge 1 commit into
KarpelesLab:masterfrom
grosmar:org-aware-accounts
Closed

grosmar wants to merge 1 commit into
KarpelesLab:masterfrom
grosmar:org-aware-accounts

Conversation

@grosmar

@grosmar grosmar commented Jun 10, 2026

Copy link
Copy Markdown

A single Claude login can belong to multiple orgs/subscriptions (e.g. a personal Max plan and a Team plan), each with its own quota. The previous code keyed OAuth accounts on account UUID alone, so two such subscriptions collapsed into one entry and could not be rotated between.

  • fetchProfile() now also returns the organization UUID and rate-limit tier
  • login / import / accounts dedupe on (accountUuid + organizationUuid), falling back to name when org info is unavailable
  • accounts are named "email (Org Name)" so multiple orgs stay distinct; accounts normalization persists this and backfills the org UUID
  • accounts listing shows org name, org type, and rate-limit tier
  • TUI dashboard shows the org per row (the field that distinguishes accounts sharing one login), and its in-dashboard import is org-aware too

A single Claude login can belong to multiple orgs/subscriptions (e.g. a
personal Max plan and a Team plan), each with its own quota. The previous
code keyed OAuth accounts on account UUID alone, so two such subscriptions
collapsed into one entry and could not be rotated between.

- fetchProfile() now also returns the organization UUID and rate-limit tier
- login / import / accounts dedupe on (accountUuid + organizationUuid),
  falling back to name when org info is unavailable
- accounts are named "email (Org Name)" so multiple orgs stay distinct;
  `accounts` normalization persists this and backfills the org UUID
- `accounts` listing shows org name, org type, and rate-limit tier
- TUI dashboard shows the org per row (the field that distinguishes
  accounts sharing one login), and its in-dashboard import is org-aware too

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@grosmar grosmar closed this Jun 10, 2026
@grosmar
grosmar deleted the org-aware-accounts branch June 10, 2026 12:04
euisan added a commit to euisan/teamclaude that referenced this pull request Oct 1, 2026
* feat(tui): fold account rows below 70 columns so usage bars wrap

On a narrow terminal (a phone over a remote session, say) an account row
could not hold its name, status and quota bars on one line. The list dropped
every bar past the first and shrank that one to a cell or two, so the weekly
and family windows vanished below 70 columns and the session bar became
unreadable near 40.

Below LIST_MIN a full-width list now folds each account into a heading
(marker, route cells, name, type, status) and one line per quota bar, with
the trailing tags wrapped a whole tag at a time beneath them. Each folded
bar takes the row less a 2-column right margin (COMPACT_BAR_RIGHT_MARGIN),
so it never touches the screen edge. The heading gives the name every
column the rest leaves, measured in display columns, so a CJK name is cut
where it reaches the type column. The smallest drawable terminal drops from
40x8 to 30x8 so the folded layout is reachable at phone widths.

This ports teamcodex KarpelesLab#21 (7296e40, compact layout below 70 columns) and
KarpelesLab#23 (0a34280, compact bar right margin), adapted to teamclaude's budgeted
_listLayout: the layout flags `narrow`, _renderRow passes the width, and
_renderAcct returns lines instead of one string. Split panes are never
narrow. teamcodex KarpelesLab#12/KarpelesLab#17/KarpelesLab#18/KarpelesLab#19 are already in 1.1.22 and were not needed.

At 70 columns and wider the frame is byte-identical to 1.1.22: the trailing
tags moved into a list but are appended in the same order with the same
separator. test/fixtures/tui-wide-frames.json holds frames recorded from the
unmodified renderer, and test/tui-narrow-bars.test.js pins both sides.

docs/teamcodex-port-plan.md classifies all 34 teamcodex commits for later
porting; docs/evidence/ holds the real TUI.start() paint at 30-80 columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(tui): use a neutral double-width name in the narrow-layout fixtures

The width tests need an account name of East Asian Wide characters, but the
one they used read like a real person's name and address. It is now
'가나다라마바사-wide@example.test': seven Hangul syllables (fourteen columns)
then ASCII, which still exercises the cases the tests care about.

- At 40 columns the name is cut exactly where it reaches the type column.
- At 30 columns a fifth syllable would straddle the edge, so it is dropped
  whole and its leftover column padded (a case the old name did not hit).
- At 69 columns the whole name fits.

The wide-frame fixture was re-recorded from the unmodified 1.1.22 renderer
with the new name. The pty capture in docs/evidence was regenerated from the
real TUI.start() paint. The comments that named the data Korean now describe
it by width. Mutating the folded heading to measure characters instead of
display columns still fails "the folded heading spends what the type and
status leave on the name, in display columns".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Euisan Kim <git@san.kim>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
euisan added a commit to euisan/teamclaude that referenced this pull request Oct 1, 2026
* feat(tui): fold account rows below 70 columns so usage bars wrap

On a narrow terminal (a phone over a remote session, say) an account row
could not hold its name, status and quota bars on one line. The list dropped
every bar past the first and shrank that one to a cell or two, so the weekly
and family windows vanished below 70 columns and the session bar became
unreadable near 40.

Below LIST_MIN a full-width list now folds each account into a heading
(marker, route cells, name, type, status) and one line per quota bar, with
the trailing tags wrapped a whole tag at a time beneath them. Each folded
bar takes the row less a 2-column right margin (COMPACT_BAR_RIGHT_MARGIN),
so it never touches the screen edge. The heading gives the name every
column the rest leaves, measured in display columns, so a CJK name is cut
where it reaches the type column. The smallest drawable terminal drops from
40x8 to 30x8 so the folded layout is reachable at phone widths.

This ports teamcodex KarpelesLab#21 (7296e40, compact layout below 70 columns) and
KarpelesLab#23 (0a34280, compact bar right margin), adapted to teamclaude's budgeted
_listLayout: the layout flags `narrow`, _renderRow passes the width, and
_renderAcct returns lines instead of one string. Split panes are never
narrow. teamcodex KarpelesLab#12/KarpelesLab#17/KarpelesLab#18/KarpelesLab#19 are already in 1.1.22 and were not needed.

At 70 columns and wider the frame is byte-identical to 1.1.22: the trailing
tags moved into a list but are appended in the same order with the same
separator. test/fixtures/tui-wide-frames.json holds frames recorded from the
unmodified renderer, and test/tui-narrow-bars.test.js pins both sides.

docs/teamcodex-port-plan.md classifies all 34 teamcodex commits for later
porting; docs/evidence/ holds the real TUI.start() paint at 30-80 columns.

* test(tui): use a neutral double-width name in the narrow-layout fixtures

The width tests need an account name of East Asian Wide characters, but the
one they used read like a real person's name and address. It is now
'가나다라마바사-wide@example.test': seven Hangul syllables (fourteen columns)
then ASCII, which still exercises the cases the tests care about.

- At 40 columns the name is cut exactly where it reaches the type column.
- At 30 columns a fifth syllable would straddle the edge, so it is dropped
  whole and its leftover column padded (a case the old name did not hit).
- At 69 columns the whole name fits.

The wide-frame fixture was re-recorded from the unmodified 1.1.22 renderer
with the new name. The pty capture in docs/evidence was regenerated from the
real TUI.start() paint. The comments that named the data Korean now describe
it by width. Mutating the folded heading to measure characters instead of
display columns still fails "the folded heading spends what the type and
status leave on the name, in display columns".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
euisan added a commit to euisan/teamclaude that referenced this pull request Oct 5, 2026
* feat(tui): fold account rows below 70 columns so usage bars wrap

On a narrow terminal (a phone over a remote session, say) an account row
could not hold its name, status and quota bars on one line. The list dropped
every bar past the first and shrank that one to a cell or two, so the weekly
and family windows vanished below 70 columns and the session bar became
unreadable near 40.

Below LIST_MIN a full-width list now folds each account into a heading
(marker, route cells, name, type, status) and one line per quota bar, with
the trailing tags wrapped a whole tag at a time beneath them. Each folded
bar takes the row less a 2-column right margin (COMPACT_BAR_RIGHT_MARGIN),
so it never touches the screen edge. The heading gives the name every
column the rest leaves, measured in display columns, so a CJK name is cut
where it reaches the type column. The smallest drawable terminal drops from
40x8 to 30x8 so the folded layout is reachable at phone widths.

This ports teamcodex KarpelesLab#21 (7296e40, compact layout below 70 columns) and
KarpelesLab#23 (0a34280, compact bar right margin), adapted to teamclaude's budgeted
_listLayout: the layout flags `narrow`, _renderRow passes the width, and
_renderAcct returns lines instead of one string. Split panes are never
narrow. teamcodex KarpelesLab#12/KarpelesLab#17/KarpelesLab#18/KarpelesLab#19 are already in 1.1.22 and were not needed.

At 70 columns and wider the frame is byte-identical to 1.1.22: the trailing
tags moved into a list but are appended in the same order with the same
separator. test/fixtures/tui-wide-frames.json holds frames recorded from the
unmodified renderer, and test/tui-narrow-bars.test.js pins both sides.

docs/teamcodex-port-plan.md classifies all 34 teamcodex commits for later
porting; docs/evidence/ holds the real TUI.start() paint at 30-80 columns.

* test(tui): use a neutral double-width name in the narrow-layout fixtures

The width tests need an account name of East Asian Wide characters, but the
one they used read like a real person's name and address. It is now
'가나다라마바사-wide@example.test': seven Hangul syllables (fourteen columns)
then ASCII, which still exercises the cases the tests care about.

- At 40 columns the name is cut exactly where it reaches the type column.
- At 30 columns a fifth syllable would straddle the edge, so it is dropped
  whole and its leftover column padded (a case the old name did not hit).
- At 69 columns the whole name fits.

The wide-frame fixture was re-recorded from the unmodified 1.1.22 renderer
with the new name. The pty capture in docs/evidence was regenerated from the
real TUI.start() paint. The comments that named the data Korean now describe
it by width. Mutating the folded heading to measure characters instead of
display columns still fails "the folded heading spends what the type and
status leave on the name, in display columns".

Reapplied on 1.1.23: tui-wide-frames.json re-recorded from the unmodified 1.1.23 renderer (percentage off by default since KarpelesLab#514); renderFrame takes a config, and the folded-label test checks percentage on and off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant