Skip to content
Open
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
22 changes: 22 additions & 0 deletions packages/cli/src/__tests__/pi-tui-mcp-status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ describe('MCP management overlay', () => {
assert.doesNotMatch(text, /尚未配置/u);
});

test('surfaces remote provider credential state without rendering a secret value', () => {
const overlay = new McpManagementOverlay({
locale: 'en',
surface: surface({
initialization: 'ready',
configuration: 'ready',
publication: 'credential_rejected',
canManagePublicationCredential: true,
toolCount: 0,
servers: [],
}),
viewportRows: () => 8,
onClose: () => undefined,
onChange: () => undefined,
});

const text = overlay.render(160).map(stripAnsi).join('\n');
assert.match(text, /provider credential rejected/u);
assert.match(text, /p Set provider credential/u);
assert.doesNotMatch(text, /maka_rh_/u);
});

test('localizes manager states without changing their source values', () => {
const overlay = new McpManagementOverlay({
locale: 'zh',
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/__tests__/runtime-host-cli-context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ test('CLI Runtime Host bootstrap launches the execution composition', async () =
assert.ok(candidateEntrypoint instanceof URL);
assert.equal(basename(fileURLToPath(candidateEntrypoint)), 'execution-candidate-main.js');
assert.ok(clientInstanceId);
assert.equal(context.clientInstanceId, clientInstanceId);
await context.close();
assert.equal(closes, 1);
});
Expand Down Expand Up @@ -309,6 +310,7 @@ test('remote CLI profiles pin root identity and resolve credential outside the p
assert.equal(remoteInput?.profile.rootId, rootId);
assert.equal(remoteInput?.credential, 'opaque-token');
assert.equal(remoteInput?.clientInstanceId, '11111111-1111-4111-8111-111111111111');
assert.equal(context.clientInstanceId, '11111111-1111-4111-8111-111111111111');
assert.equal(Object.hasOwn(context.profile, 'credential'), false);
await context.close();
});
Expand Down
69 changes: 68 additions & 1 deletion packages/cli/src/__tests__/tui-mcp-control.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import type {
RuntimeHostConnectionAvailability,
} from '@maka/runtime-host/client';
import { createMcpConfigStore } from '@maka/storage/mcp-config-store';
import { createTuiMcpController } from '../tui-mcp-control.js';
import { createTuiMcpController, type TuiMcpPublicationAvailability } from '../tui-mcp-control.js';
import { waitFor } from './tui-terminal-mock.js';

test('TUI MCP startup stays backgrounded and publishes the discovered snapshot', async () => {
Expand Down Expand Up @@ -71,6 +71,73 @@ test('TUI MCP startup stays backgrounded and publishes the discovered snapshot',
assert.equal(manager.closed, 1);
});

test('TUI MCP serializes remote provider credential changes through its publication lane', async () => {
let availability: TuiMcpPublicationAvailability = {
kind: 'unavailable',
reason: 'credential_required',
};
let listener: ((value: TuiMcpPublicationAvailability) => void) | undefined;
const credentials: string[] = [];
let removed = 0;
let closed = 0;
const connection = {
replaceClientCapabilities: async () => ({ registrationId: 'registration', revision: 1 }),
unregisterClientCapabilities: async () => ({ registrationId: 'registration', revision: 1 }),
subscribeConnectionAvailability: (next: (value: TuiMcpPublicationAvailability) => void) => {
listener = next;
next(availability);
return () => {
if (listener === next) listener = undefined;
};
},
setCredential: async (credential: string) => {
credentials.push(credential);
availability = { kind: 'connected', hostEpoch: 'host-1', connectionId: 'provider-1' };
listener?.(availability);
},
removeCredential: async () => {
removed += 1;
availability = { kind: 'unavailable', reason: 'credential_required' };
listener?.(availability);
},
closePublication: async () => {
closed += 1;
},
};
const manager = managerHarness(0, []);
const controller = createTuiMcpController(
{ workspaceRoot: '/unused', connection },
{
configStore: configStoreHarness(async () => emptyConfig()),
manager: manager.manager,
createProvider: () => undefined,
},
);
await waitFor(
() => controller.snapshot().initialization === 'ready',
'remote MCP controller initialization',
);
assert.equal(controller.snapshot().publication, 'credential_required');
assert.equal(controller.snapshot().canManagePublicationCredential, true);

assert.deepEqual(
await controller.execute({
kind: 'set_publication_credential',
credential: 'provider-secret',
}),
{ status: 'applied', effect: 'published' },
);
assert.deepEqual(credentials, ['provider-secret']);
assert.deepEqual(await controller.execute({ kind: 'remove_publication_credential' }), {
status: 'applied',
effect: 'pending_host',
});
assert.equal(removed, 1);
assert.equal(controller.snapshot().publication, 'credential_required');
await controller.close();
assert.equal(closed, 1);
});

test('TUI MCP publication coalesces a discovery change behind the in-flight revision', async () => {
const manager = managerHarness(1, [connectedStatus('local', 1)]);
const connection = connectionHarness();
Expand Down
Loading