feat: pass managed runtime policy through setup

This commit is contained in:
Andrey Avtomonov 2026-05-11 11:06:46 +02:00
parent fc548e96e8
commit 35d8ced934
5 changed files with 81 additions and 1 deletions

View file

@ -179,6 +179,7 @@ async function runBareInteractiveCommand(
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: context.packageInfo.version,
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],

View file

@ -371,6 +371,7 @@ export function registerSetupCommands(program: Command, context: KtxCliCommandCo
skipAgents: options.skipAgents === true,
inputMode: options.input === false ? 'disabled' : 'auto',
yes: options.yes === true,
cliVersion: context.packageInfo.version,
...(options.anthropicApiKeyEnv ? { anthropicApiKeyEnv: options.anthropicApiKeyEnv } : {}),
...(options.anthropicApiKeyFile ? { anthropicApiKeyFile: options.anthropicApiKeyFile } : {}),
...(options.anthropicModel ? { anthropicModel: options.anthropicModel } : {}),

View file

@ -324,6 +324,7 @@ describe('runKtxCli', () => {
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.0.0-private',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -1015,6 +1016,7 @@ describe('runKtxCli', () => {
command: 'run',
projectDir: tempDir,
inputMode: 'disabled',
cliVersion: '0.0.0-private',
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY',
anthropicModel: 'claude-sonnet-4-6',
skipLlm: false,
@ -1122,6 +1124,7 @@ describe('runKtxCli', () => {
projectDir: '/tmp/project',
inputMode: 'disabled',
yes: true,
cliVersion: '0.0.0-private',
skipLlm: true,
skipEmbeddings: true,
databaseDrivers: ['postgres'],

View file

@ -318,6 +318,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
databaseSchemas: [],
@ -364,6 +365,7 @@ describe('setup status', () => {
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -410,6 +412,7 @@ describe('setup status', () => {
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -434,6 +437,7 @@ describe('setup status', () => {
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -472,6 +476,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
databaseSchemas: [],
@ -530,6 +535,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
databaseSchemas: [],
@ -597,6 +603,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
databaseSchemas: [],
@ -661,6 +668,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: true,
databaseSchemas: [],
@ -697,6 +705,7 @@ describe('setup status', () => {
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -733,6 +742,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
databaseSchemas: [],
@ -764,6 +774,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
databaseSchemas: [],
@ -791,6 +802,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: true,
databaseSchemas: [],
@ -819,6 +831,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY',
anthropicModel: 'claude-sonnet-4-6',
skipLlm: false,
@ -858,7 +871,8 @@ describe('setup status', () => {
agents: false,
skipAgents: true,
inputMode: 'disabled',
yes: false,
yes: true,
cliVersion: '0.2.0',
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY',
anthropicModel: 'claude-sonnet-4-6',
skipLlm: false,
@ -878,6 +892,8 @@ describe('setup status', () => {
expect.objectContaining({
projectDir: tempDir,
inputMode: 'disabled',
cliVersion: '0.2.0',
runtimeInstallPolicy: 'auto',
embeddingBackend: 'openai',
embeddingApiKeyEnv: 'OPENAI_API_KEY',
skipEmbeddings: false,
@ -886,6 +902,43 @@ describe('setup status', () => {
);
});
it('passes no-input runtime policy to the embeddings step', async () => {
const io = makeIo();
const embeddings = vi.fn(async () => ({ status: 'failed' as const, projectDir: tempDir }));
await expect(
runKtxSetup(
{
command: 'run',
projectDir: tempDir,
mode: 'new',
agents: false,
agentScope: 'project',
agentInstallMode: 'cli',
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: false,
databaseSchemas: [],
skipDatabases: true,
skipSources: true,
},
io.io,
{ embeddings },
),
).resolves.toBe(1);
expect(embeddings).toHaveBeenCalledWith(
expect.objectContaining({
cliVersion: '0.2.0',
runtimeInstallPolicy: 'never',
}),
io.io,
);
});
it('lets Back from embedding setup return to the model step instead of exiting', async () => {
const testIo = makeIo();
const modelResults = [
@ -905,6 +958,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -952,6 +1006,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -997,6 +1052,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: true,
databaseSchemas: [],
@ -1037,6 +1093,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY',
anthropicModel: 'claude-sonnet-4-6',
skipLlm: false,
@ -1084,6 +1141,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
skipDatabases: true,
@ -1130,6 +1188,7 @@ describe('setup status', () => {
agents: false,
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
skipDatabases: true,
@ -1191,6 +1250,7 @@ describe('setup status', () => {
agentInstallMode: 'cli',
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
skipDatabases: true,
@ -1244,6 +1304,7 @@ describe('setup status', () => {
agentInstallMode: 'cli',
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
skipDatabases: true,
@ -1277,6 +1338,7 @@ describe('setup status', () => {
agents: false,
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: true,
skipEmbeddings: true,
skipDatabases: true,
@ -1375,6 +1437,7 @@ describe('setup status', () => {
agents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
skipDatabases: false,
@ -1437,6 +1500,7 @@ describe('setup status', () => {
agentInstallMode: 'both',
inputMode: 'disabled',
yes: true,
cliVersion: '0.2.0',
skipLlm: false,
skipEmbeddings: false,
skipDatabases: false,
@ -1485,6 +1549,7 @@ describe('setup status', () => {
skipAgents: true,
inputMode: 'disabled',
yes: false,
cliVersion: '0.2.0',
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY',
anthropicModel: 'claude-sonnet-4-6',
skipLlm: false,

View file

@ -60,6 +60,7 @@ export type KtxSetupArgs =
skipAgents?: boolean;
inputMode: 'auto' | 'disabled';
yes: boolean;
cliVersion: string;
anthropicApiKeyEnv?: string;
anthropicApiKeyFile?: string;
anthropicModel?: string;
@ -397,6 +398,13 @@ function writeContextNotReadyForAgents(projectDir: string, io: KtxCliIo): void {
io.stderr.write(`Then install agent integration:\n ktx setup --agents --project-dir ${resolve(projectDir)}\n`);
}
function setupRuntimeInstallPolicy(args: Extract<KtxSetupArgs, { command: 'run' }>): 'prompt' | 'auto' | 'never' {
if (args.yes) {
return 'auto';
}
return args.inputMode === 'disabled' ? 'never' : 'prompt';
}
export async function runKtxSetup(args: KtxSetupArgs, io: KtxCliIo, deps: KtxSetupDeps = {}): Promise<number> {
try {
return await runKtxSetupInner(args, io, deps);
@ -566,6 +574,8 @@ async function runKtxSetupInner(args: KtxSetupArgs, io: KtxCliIo, deps: KtxSetup
{
projectDir: projectResult.projectDir,
inputMode: args.inputMode,
cliVersion: args.cliVersion,
runtimeInstallPolicy: setupRuntimeInstallPolicy(args),
...(args.embeddingBackend ? { embeddingBackend: args.embeddingBackend } : {}),
...(args.embeddingApiKeyEnv ? { embeddingApiKeyEnv: args.embeddingApiKeyEnv } : {}),
...(args.embeddingApiKeyFile ? { embeddingApiKeyFile: args.embeddingApiKeyFile } : {}),