initial transfer

This commit is contained in:
Benjamin Diedrichsen
2026-07-27 13:09:00 +02:00
parent 9f25d48dc2
commit 736c01216a
191 changed files with 17622 additions and 136 deletions
+174
View File
@@ -0,0 +1,174 @@
/**
* Interactive prompts for nopy CLI
* @module nopy.prompts
*/
// @ts-ignore - no types available
import Enquirer from 'enquirer';
import fuzzy from 'fuzzy';
import inquirer from 'inquirer';
// @ts-ignore - no types available
import CheckboxPlus from 'inquirer-checkbox-plus-prompt';
import { z } from 'zod';
// Register the checkbox-plus prompt type for filterable multi-select
inquirer.registerPrompt('checkbox-plus', CheckboxPlus);
/**
* Prompts the user to select cubes to execute with filtering support
*/
export async function CubeSelection(cubes) {
const cubeChoices = Object.values(cubes)
.sort((a, b) => a.id.localeCompare(b.id))
.map((cube) => ({
name: `${cube.id} - ${cube.name}`,
value: cube.id,
short: cube.id,
}));
// Clear terminal and move cursor to top
process.stdout.write('\x1B[2J\x1B[0f');
const terminalHeight = process.stdout.rows || 24;
const pageSize = Math.max(10, terminalHeight - 5);
console.log('\n Cube Selection\n');
console.log(' Type to filter • Space to select • Enter to confirm\n');
const answers = await inquirer.prompt([
{
type: 'checkbox-plus',
name: 'selectedCubes',
message: 'Select cubes:',
pageSize,
highlight: true,
searchable: true,
source: (_answersSoFar, input) => {
const searchTerm = input || '';
if (!searchTerm)
return Promise.resolve(cubeChoices);
const results = fuzzy.filter(searchTerm, cubeChoices, {
extract: (choice) => choice.name,
});
return Promise.resolve(results.map((r) => r.original));
},
},
]);
return { selectedCubes: answers.selectedCubes };
}
export async function AuthSelection(useAuthKey) {
if (useAuthKey)
return { authMethod: 'ssh-key' };
const answers = await inquirer.prompt([
{
type: 'list',
name: 'authMethod',
message: 'Select authentication method:',
choices: ['ssh-key', 'password'],
},
{
type: 'input',
name: 'username',
message: 'Enter username:',
when: (answers) => answers.authMethod !== 'ssh-key',
},
{
type: 'password',
name: 'password',
message: 'Enter password:',
when: (answers) => answers.authMethod !== 'ssh-key',
},
]);
return answers;
}
export async function PasswordSelection(username) {
const { password } = await inquirer.prompt([
{
type: 'password',
name: 'password',
message: `Enter password for ${username}:`,
},
]);
return password;
}
export async function HostSelection(hosts) {
const selectedHost = await inquirer.prompt([
{
type: 'list',
name: 'host',
message: 'Select host from inventory',
choices: ['docker', 'vagrant', ...hosts, 'custom'],
},
{
type: 'input',
name: 'customHost',
message: 'Specify custom host address:',
when: (answers) => answers.host === 'custom',
},
{
type: 'input',
name: 'vagrantVM',
message: 'Specify vagrant machine:',
default: 'default',
when: (answers) => answers.host === 'vagrant',
},
{
type: 'input',
name: 'dockerContainer',
message: 'Specify docker container name:',
when: (answers) => answers.host === 'runtime:docker',
},
]);
if (selectedHost.host === 'vagrant')
return `@vagrant/${selectedHost.vagrantVM}`;
if (selectedHost.host === 'runtime:docker')
return `@docker/${selectedHost.dockerContainer}`;
return selectedHost.customHost ?? selectedHost.host;
}
function coerceValue(value, zodType) {
if (typeof value !== 'string')
return value;
if (zodType instanceof z.ZodDefault)
return coerceValue(value, zodType._def.innerType);
if (zodType instanceof z.ZodOptional)
return coerceValue(value, zodType._def.innerType);
if (zodType instanceof z.ZodNullable) {
if (value === 'null' || value === '')
return null;
return coerceValue(value, zodType._def.innerType);
}
if (zodType instanceof z.ZodBoolean)
return value === 'true' || value === 'yes' || value === '1';
if (zodType instanceof z.ZodNumber) {
const num = Number(value);
return Number.isNaN(num) ? value : num;
}
return value;
}
export async function VariableAssignment(cube, variables) {
const schema = cube.manifest.schema.shape;
const defaults = cube.getDefaults();
const variablesToConfigure = {};
for (const [key, defaultValue] of Object.entries(defaults)) {
if (variables.get(cube.id, 'params')[key] === undefined) {
variablesToConfigure[key] = defaultValue;
}
}
if (Object.keys(variablesToConfigure).length === 0)
return;
const choices = Object.entries(variablesToConfigure).map(([key, value]) => {
const zodType = schema[key];
const description = zodType?.description || key;
return { name: key, message: description, initial: String(value ?? '') };
});
const form = new Enquirer.Form({
name: 'variables',
message: `[${cube.id}] ${cube.name}\n (↑↓ navigate, Enter to submit)`,
choices,
});
try {
const result = await form.run();
const coercedResult = {};
for (const [key, value] of Object.entries(result)) {
const zodType = schema[key];
coercedResult[key] = zodType ? coerceValue(value, zodType) : value;
}
variables.assign(cube.id, 'prompts', coercedResult);
}
catch {
// User cancelled
}
}