Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions frontend/src/v2/__tests__/V2YourTeamPage.where.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,21 @@ const agent = (overrides) => ({

const agents = [
agent({ name: 'scout', displayName: 'Scout', userId: 'user-scout', installedBy: 'me', runtime: { runtimeType: 'hosted' } }),
agent({ name: 'stampedhost', displayName: 'Stampedhost', userId: 'user-stampedhost', runtime: { runtimeType: 'codex', host: 'cloud' } }),
agent({ name: 'codex', displayName: 'Codex', userId: 'user-codex', runtime: { runtimeType: 'codex' } }),
agent({ name: 'agentrun', displayName: 'Agentrun', userId: 'user-agentrun', installedBy: 'me', runtime: { runtimeType: 'codex' } }),
agent({ name: 'laptop', displayName: 'Laptop', userId: 'user-laptop', installedBy: 'me', runtime: { runtimeType: 'native', host: 'byo' } }),
agent({ name: 'hook', displayName: 'Hook', userId: 'user-hook', installedBy: 'me', runtime: { runtimeType: 'webhook' } }),
agent({ name: 'daemon', displayName: 'Daemon', userId: 'user-daemon', installedBy: 'me', runtime: { runtimeType: 'wrapper', adapter: 'codex' } }),
agent({ name: 'teammate', displayName: 'Teammate', userId: 'user-teammate', installedBy: 'someone-else', runtime: { runtimeType: 'webhook' } }),
agent({ name: 'teamdaemon', displayName: 'Teamdaemon', userId: 'user-teamdaemon', installedBy: 'someone-else', runtime: { runtimeType: 'wrapper', adapter: 'codex' } }),
agent({ name: 'hook', displayName: 'Hook', userId: 'user-hook', installedBy: 'me', runtime: { runtimeType: 'webhook', host: 'byo' } }),
agent({ name: 'daemon', displayName: 'Daemon', userId: 'user-daemon', installedBy: 'me', runtime: { runtimeType: 'wrapper', adapter: 'codex', host: 'byo' } }),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
agent({ name: 'teammate', displayName: 'Teammate', userId: 'user-teammate', installedBy: 'someone-else', runtime: { runtimeType: 'webhook', host: 'byo' } }),
agent({ name: 'teamdaemon', displayName: 'Teamdaemon', userId: 'user-teamdaemon', installedBy: 'someone-else', runtime: { runtimeType: 'wrapper', adapter: 'codex', host: 'byo' } }),
agent({ name: 'cloudhost', displayName: 'Cloudhost', userId: 'user-cloudhost', runtime: { runtimeType: 'something-new', host: 'cloud' } }),
agent({ name: 'mystery', displayName: 'Mystery', userId: 'user-mystery', runtime: { runtimeType: 'something-new' } }),
agent({ name: 'hookowned', displayName: 'Hookowned', userId: 'user-hookowned', installedBy: 'me', runtime: { runtimeType: 'webhook' } }),
agent({ name: 'wrapnohost', displayName: 'Wrapnohost', userId: 'user-wrapnohost', installedBy: 'me', runtime: { runtimeType: 'wrapper', adapter: 'codex' } }),
agent({ name: 'nativeunstamped', displayName: 'Nativeunstamped', userId: 'user-nativeunstamped', runtime: { runtimeType: 'native' } }),
agent({ name: 'internalunstamped', displayName: 'Internalunstamped', userId: 'user-internalunstamped', runtime: { runtimeType: 'internal' } }),
agent({ name: 'moltbotunstamped', displayName: 'Moltbotunstamped', userId: 'user-moltbotunstamped', runtime: { runtimeType: 'moltbot' } }),
];

const renderPage = () => render(
Expand Down Expand Up @@ -74,15 +81,26 @@ describe('V2YourTeamPage location mark and hosted meter', () => {
renderPage();
const cardOf = async (name) => (await screen.findByText(name)).closest('article');
expect(within(await cardOf('Scout')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
expect(within(await cardOf('Codex')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
// A hosted seat with no stamp is cloud by its type: it has no BYO form.
// A codex seat with no host stamp gets no mark: codex can run on someone's machine.
expect(within(await cardOf('Codex')).queryByRole('img', { name: /Runs on/ })).toBeNull();
expect(within(await cardOf('Agentrun')).queryByRole('img', { name: /Runs on/ })).toBeNull();
expect(within(await cardOf('Laptop')).getByRole('img', { name: 'Runs on your computer' })).toBeInTheDocument();
expect(within(await cardOf('Hook')).getByRole('img', { name: 'Runs on your computer' })).toBeInTheDocument();
expect(within(await cardOf('Cloudhost')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
expect(within(await cardOf('Stampedhost')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
// A teammate's laptop seat: we don't know which machine it runs on.
expect(within(await cardOf('Teammate')).queryByRole('img', { name: /Runs on/ })).toBeNull();
expect(within(await cardOf('Daemon')).getByRole('img', { name: 'Runs on your computer' })).toBeInTheDocument();
expect(within(await cardOf('Teamdaemon')).queryByRole('img', { name: /Runs on/ })).toBeNull();
expect(within(await cardOf('Mystery')).queryByRole('img', { name: /Runs on/ })).toBeNull();
// No host stamp and a BYO type: no mark, even for the installer's own seat.
expect(within(await cardOf('Hookowned')).queryByRole('img', { name: /Runs on/ })).toBeNull();
expect(within(await cardOf('Wrapnohost')).queryByRole('img', { name: /Runs on/ })).toBeNull();
// Cloud-only runtime types with no stamp read as cloud.
expect(within(await cardOf('Nativeunstamped')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
expect(within(await cardOf('Internalunstamped')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
expect(within(await cardOf('Moltbotunstamped')).getByRole('img', { name: 'Runs on Commonly' })).toBeInTheDocument();
// The own-agent tile is the viewer's own machine by definition.
expect(screen.getByTestId('team-own-card').querySelector('[role="img"]')).not.toBeNull();
});
Expand Down
24 changes: 11 additions & 13 deletions frontend/src/v2/components/V2YourTeamPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,23 +103,21 @@ const STATE_DOT = '\u25CF';

const agentKey = (a: { name: string; instanceId?: string }) => `${a.name}:${a.instanceId || 'default'}`;

// Where a seat runs, mirroring agentIdentityService.isCloudRuntime (host first).
// 'hosted' is the ADR-023 hosted runtime, which Commonly runs, so it is cloud even
// though isCloudRuntime excludes it from the operator gate. A seat we can't
// classify gets no mark rather than a guessed one.
// A laptop mark means the viewer's own machine, so a seat another teammate installed
// gets no laptop mark: we don't know which machine it runs on.
// Where a seat runs. A stamped host decides it: config.runtime.host is 'cloud'
// (Commonly runs it) or 'byo' (a machine polling in). A runtime type with no BYO
// form has only one possible location, so it reads as cloud without a stamp:
// hosted, native, internal and moltbot (the cluster gateway). Nothing stamps host
// on a new hosted install, so these need the type. Every other type (codex,
// claude-code, webhook, wrapper) can run on someone's machine, so it gets no mark
// unless its host is stamped. A laptop mark means the viewer's own machine, so a
// byo seat another teammate installed gets no laptop mark either.
type RunsOn = 'cloud' | 'laptop' | null;
const CLOUD_RUNTIME_TYPES = new Set(['hosted', 'moltbot', 'internal', 'native', 'managed-agents', 'codex']);
// 'wrapper' is a daemon-bound seat (pod-agents projects it over the harness label).
const BYO_RUNTIME_TYPES = new Set(['webhook', 'claude-code', 'wrapper']);
const CLOUD_ONLY_RUNTIME_TYPES = new Set(['hosted', 'native', 'internal', 'moltbot']);
const runsOn = (a: AgentInstallationSummary, viewerId: string | undefined): RunsOn => {
const type = (a.runtime?.runtimeType || '').trim().toLowerCase();
const host = (a.runtime?.host || '').trim().toLowerCase();
if (host === 'cloud') return 'cloud';
const type = (a.runtime?.runtimeType || '').trim().toLowerCase();
if (host === 'cloud' || (!host && CLOUD_ONLY_RUNTIME_TYPES.has(type))) return 'cloud';
if (host === 'byo') return a.installedBy === viewerId ? 'laptop' : null;
if (CLOUD_RUNTIME_TYPES.has(type)) return 'cloud';
if (BYO_RUNTIME_TYPES.has(type)) return a.installedBy === viewerId ? 'laptop' : null;
return null;
};

Expand Down
Loading