refactor(cli): centralize Clack prompt handling

This commit is contained in:
Andrey Avtomonov 2026-05-12 11:31:43 +02:00
parent 9409d50d1d
commit 42365481ac
3 changed files with 106 additions and 12 deletions

View file

@ -214,6 +214,7 @@ describe('createManagedPythonSemanticLayerComputePort', () => {
expect(confirmInstall).toHaveBeenCalledWith(
'KTX needs to install the core Python runtime. This downloads Python dependencies with uv. Continue?',
io.io,
);
expect(installRuntime).toHaveBeenCalledWith({
cliVersion: '0.2.0',
@ -221,4 +222,45 @@ describe('createManagedPythonSemanticLayerComputePort', () => {
force: false,
});
});
it('uses injected runtime confirmation instead of reading process TTY directly', async () => {
const io = makeIo();
const compute = { query: vi.fn(), validateSources: vi.fn(), generateSources: vi.fn() };
const installRuntime = vi.fn(async (): Promise<ManagedPythonRuntimeInstallResult> => installResult());
const confirmInstall = vi.fn(async () => true);
await expect(
createManagedPythonSemanticLayerComputePort({
cliVersion: '0.2.0',
installPolicy: 'prompt',
io: io.io,
readStatus: async () => missingStatus(),
installRuntime,
confirmInstall,
createPythonCompute: () => compute,
}),
).resolves.toBe(compute);
expect(confirmInstall).toHaveBeenCalledWith(
'KTX needs to install the core Python runtime. This downloads Python dependencies with uv. Continue?',
io.io,
);
expect(io.stderr()).toContain('Installing KTX Python runtime (core) with uv...');
});
it('can decide default runtime prompting from injected io capabilities', async () => {
const io = makeIo();
Object.assign(io.io.stdout, { isTTY: false });
await expect(
createManagedPythonSemanticLayerComputePort({
cliVersion: '0.2.0',
installPolicy: 'prompt',
io: io.io,
readStatus: async () => missingStatus(),
installRuntime: vi.fn(),
createPythonCompute: () => ({ query: vi.fn(), validateSources: vi.fn(), generateSources: vi.fn() }),
}),
).rejects.toThrow('KTX Python runtime installation was cancelled');
});
});