feat(cli): enforce required database selection and improve tree-picker UX (#86)

* feat(cli): enforce required database selection and improve tree-picker UX

- Require at least one database driver via prompt `required: true` instead of
  looping on empty selection; remove the now-dead retry/back-on-empty branch.
- Surface the recommended option with a "(recommended)" hint in the depth and
  query-history prompts.
- Tree picker: add `◧` partial glyph for parents whose descendants are checked,
  and make `a` toggle select-all-visible / select-none.

* fix(cli): drop unused export from tree-picker toggleSelectAllVisible

Knip flagged the export as unused; the function is only consumed by the
internal reducer via the 'toggle-select-all-visible' command, so demote
it to a module-local helper to keep CI's dead-code check green.

* test(cli): drop empty-selection warning assertion from setup test

The empty-selection retry/warning loop in `chooseDrivers` was removed in
favor of `multiselect`'s `required: true`, so the legacy warning string
is unreachable. Update the test to assert the simpler back-from-selection
return-to-embeddings flow.
This commit is contained in:
Andrey Avtomonov 2026-05-14 14:35:58 +02:00 committed by GitHub
parent e28b10454a
commit 6c4623f2ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 146 additions and 60 deletions

View file

@ -932,7 +932,7 @@ async function maybeApplyHistoricSqlConfig(input: {
const choice = await input.prompts.select({
message: `Enable query-history ingest for this ${driverLabel(input.driver)} connection?`,
options: [
{ value: 'yes', label: 'Enable query history' },
{ value: 'yes', label: 'Enable query history (recommended)' },
{ value: 'no', label: 'Do not enable query history' },
{ value: 'back', label: 'Back' },
],
@ -1756,27 +1756,17 @@ async function chooseDrivers(
);
return 'missing-input';
}
while (true) {
const initialValues = unique(options?.initialDrivers ?? []);
const choices = await prompts.multiselect({
message: withMultiselectNavigation('Which databases should KTX connect to?'),
options: [...DRIVER_OPTIONS],
...(initialValues.length > 0 ? { initialValues } : {}),
required: options?.hasPrimarySources === true,
});
if (choices.includes('back')) {
return 'back';
}
if (choices.length > 0) {
return choices as KtxSetupDatabaseDriver[];
}
if (options?.hasPrimarySources) {
return 'back';
}
io.stdout.write('│ KTX cannot work without at least one database. Select a database or press Escape to go back.\n');
const initialValues = unique(options?.initialDrivers ?? []);
const choices = await prompts.multiselect({
message: withMultiselectNavigation('Which databases should KTX connect to?'),
options: [...DRIVER_OPTIONS],
...(initialValues.length > 0 ? { initialValues } : {}),
required: true,
});
if (choices.includes('back')) {
return 'back';
}
return choices as KtxSetupDatabaseDriver[];
}
async function chooseConnectionIdForDriver(input: {