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
49 changes: 49 additions & 0 deletions backend/__tests__/unit/services/byoHandoffService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,53 @@ describe('byoHandoffService', () => {
expect(defaultByoHandoffName('Sam Xu', 'claude')).toBe('sam-xu-claude');
expect(defaultByoHandoffName(undefined, 'codex')).toBe('my-codex');
});

describe('login line', () => {
const ENV_KEYS = ['PUBLIC_API_URL', 'BACKEND_URL'];
let saved;

beforeEach(() => {
saved = ENV_KEYS.map((key) => [key, process.env[key]]);
ENV_KEYS.forEach((key) => { delete process.env[key]; });
});

afterEach(() => {
saved.forEach(([key, value]) => {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
});
});

const loginLineFor = (os) => {
const payload = buildByoHandoffPayload({
adapter: 'codex', os, podId: 'pod-1', agentName: 'my-codex',
});
if ('error' in payload) throw new Error(payload.error);
return payload.commands[os].split('\n')[1];
};

it('stays a bare login when the server has no public origin configured', () => {
expect(loginLineFor('linux')).toBe('commonly login');
});

it('names the server origin on every OS when BACKEND_URL is set', () => {
process.env.BACKEND_URL = 'http://localhost:5000';
for (const os of ['mac', 'linux', 'windows']) {
expect(loginLineFor(os)).toBe('commonly login --instance http://localhost:5000');
}
});

it('prefers PUBLIC_API_URL and reduces it to the bare origin', () => {
process.env.BACKEND_URL = 'http://backend.internal:5000';
process.env.PUBLIC_API_URL = 'https://api.commonly.me/api?token=x#frag';
expect(loginLineFor('mac')).toBe('commonly login --instance https://api.commonly.me');
});

it('drops a configured value that is not a plain http(s) origin', () => {
for (const unsafe of ['file:///etc/passwd', 'ftp://api.commonly.me', 'http://$(id)', 'not a url']) {
process.env.PUBLIC_API_URL = unsafe;
expect(loginLineFor('mac')).toBe('commonly login');
}
});
});
});
23 changes: 21 additions & 2 deletions backend/services/byoHandoffService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ const safeName = (value: unknown): string => String(value || '')

const safePodId = (value: unknown): string => String(value || '').trim().replace(/[^a-zA-Z0-9_-]/g, '');

// The instance this server answers on. A bare `commonly login` falls back to
// the CLI's built-in production default, so a card posted by a dev or
// self-hosted server would register the person's computer against commonly.me.
// Only a plain http(s) origin is composed into the shell line.
const PLAIN_ORIGIN = /^https?:\/\/[a-z0-9.-]+(:\d{1,5})?$/i;
const publicApiOrigin = (): string => {
try {
const { origin } = new URL(process.env.PUBLIC_API_URL || process.env.BACKEND_URL || '');
return PLAIN_ORIGIN.test(origin) ? origin : '';
} catch {
return '';
}
};

const environmentPath = (os: ByoHandoffOs): string => {
if (os === 'windows') return 'C:\\Users\\you\\agents\\environment.json';
if (os === 'linux') return '/home/you/agents/environment.json';
Expand All @@ -58,20 +72,23 @@ export const buildByoHandoffCommand = ({
agentName,
memoryFrom,
memoryInstance = 'default',
apiOrigin = '',
}: {
adapter: ByoHandoffAdapter;
os: ByoHandoffOs;
podId: string;
agentName: string;
memoryFrom?: string;
memoryInstance?: string;
apiOrigin?: string;
}): string => {
const memoryFlags = memoryFrom ? ` --memory-from ${memoryFrom} --memory-instance ${memoryInstance}` : '';
const attach = `commonly agent attach ${adapter} --pod ${podId} --name ${agentName}${memoryFlags}`;
const withEnvironment = adapter === 'opencode' || adapter === 'dsh'
? `${attach} --env ${environmentPath(os)}`
: attach;
return [installCommand(adapter), 'commonly login', withEnvironment, `commonly agent run ${agentName}`].join('\n');
const login = apiOrigin ? `commonly login --instance ${apiOrigin}` : 'commonly login';
return [installCommand(adapter), login, withEnvironment, `commonly agent run ${agentName}`].join('\n');
};

export interface ByoHandoffPayload {
Expand All @@ -91,13 +108,15 @@ export const buildByoHandoffPayload = ({
agentName,
memoryFrom,
memoryInstance = 'default',
apiOrigin = publicApiOrigin(),
}: {
adapter: unknown;
os: unknown;
podId: unknown;
agentName: unknown;
memoryFrom?: string;
memoryInstance?: string;
apiOrigin?: string;
}): ByoHandoffPayload | { error: string } => {
if (!isAdapter(adapter)) return { error: 'adapter must be claude, codex, opencode, or dsh' };
if (!isOs(os)) return { error: 'os must be mac, linux, or windows' };
Expand All @@ -120,7 +139,7 @@ export const buildByoHandoffPayload = ({
for (const supported of supportedOs) {
commands[supported] = buildByoHandoffCommand({
adapter, os: supported, podId: normalizedPodId, agentName: normalizedName,
memoryFrom, memoryInstance,
memoryFrom, memoryInstance, apiOrigin,
});
}
return {
Expand Down
Loading