feat(setup): wizard prompt tweaks and quieter query-history filter output (#259)

Setup wizard flow tweaks:
- Add a reveal-tail password prompt (reveal-password-prompt.ts) that unmasks
  the last few characters of a typed/pasted secret, and wire it into the setup
  prompt adapter in place of clack's password(); adds the @clack/core dep.
- Reorder wizard select options: surface "Paste a key" before the
  environment-variable option across embeddings/models/sources, promote
  Metabase/Notion in the source list, put Git URL before Local path, reorder
  the Notion crawl-mode choices, and relabel the sources "Done" action.

Query-history filter picker output:
- Collapse the per-template parse-failure lines into a single count in the
  setup output and route the full template-id list to --debug stderr.
- Model parse failures as a structured parseFailedTemplateIds field instead of
  warning strings.
- Add a privacy-safe query_history_filter_completed telemetry event
  (counts/enums only), mirrored into the Python daemon schema.
This commit is contained in:
Andrey Avtomonov 2026-06-04 14:11:08 +02:00 committed by GitHub
parent 8eb1cd3e79
commit c2beaf7d55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 494 additions and 34 deletions

View file

@ -2654,6 +2654,7 @@ describe('setup databases step', () => {
consideredRoleCount: 2,
skipped: null,
warnings: [],
parseFailedTemplateIds: [],
}));
const result = await runKtxSetupDatabasesStep(
@ -2706,6 +2707,54 @@ describe('setup databases step', () => {
expect(io.stdout()).toContain('svc_loader');
});
it('collapses query-history parse failures to a count and lists ids only with --debug', async () => {
const io = makeIo();
const queryHistoryFilterPicker = vi.fn(async () => ({
excludedRoles: [],
consideredRoleCount: 1,
skipped: { reason: 'no-in-scope-history' as const },
warnings: [],
parseFailedTemplateIds: ['111', '222'],
}));
const result = await runKtxSetupDatabasesStep(
{
projectDir: tempDir,
inputMode: 'disabled',
debug: true,
yes: true,
databaseDrivers: ['postgres'],
databaseConnectionId: 'warehouse',
databaseUrl: 'env:DATABASE_URL',
databaseSchemas: ['public'],
enableQueryHistory: true,
skipDatabases: false,
},
io.io,
{
testConnection: vi.fn(async () => 0),
scanConnection: vi.fn(async () => 0),
historicSqlReadinessProbe: vi.fn(async () => {
const runner = fakeHistoricSqlRunner('postgres', 'pg_stat_statements');
return {
ok: true as const,
dialect: 'postgres' as const,
runner,
result: { pgServerVersion: 'PostgreSQL 16.4', warnings: [], info: [] },
};
}),
queryHistoryFilterPicker,
createQueryHistoryLlmRuntime: vi.fn(() => null),
},
);
expect(result.status).toBe('ready');
expect(io.stdout()).toContain('Skipped 2 query templates ktx could not parse');
expect(io.stdout()).not.toContain('111');
expect(io.stdout()).not.toContain('222');
expect(io.stderr()).toContain('could not parse 2 template(s): 111, 222');
});
it('lets interactive setup skip applying derived filters', async () => {
const io = makeIo();
const prompts = makePromptAdapter({
@ -2743,6 +2792,7 @@ describe('setup databases step', () => {
consideredRoleCount: 2,
skipped: null,
warnings: [],
parseFailedTemplateIds: [],
})),
createQueryHistoryLlmRuntime: vi.fn(() => null),
},
@ -2811,6 +2861,7 @@ describe('setup databases step', () => {
consideredRoleCount: 2,
skipped: { reason: 'user-block-present' as const },
warnings: [],
parseFailedTemplateIds: [],
})),
createQueryHistoryLlmRuntime: vi.fn(() => null),
},