feat: add setup channel verification checklist output

This commit is contained in:
William Valentin
2026-02-18 10:48:49 -08:00
parent 8234cc93f3
commit 49f0e0598b
5 changed files with 88 additions and 3 deletions
+14
View File
@@ -13,6 +13,8 @@ import {
getMinioExtractorInstallHints,
renderMinioExtractorSetupLines,
} from './minioExtractors.js';
import { renderOnboardingChecklist } from './setup/summary.js';
import type { SetupConfig } from './setup/config.js';
export async function runSetup(configPath: string): Promise<void> {
const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -27,6 +29,7 @@ export async function runSetup(configPath: string): Promise<void> {
await runMenu(p, builder);
saveConfig(configPath, builder, p);
const config = builder.build();
printOnboardingChecklist(p, config as Record<string, unknown>, configPath);
await printMinioExtractorSetupStatus(p, config as Record<string, unknown>);
await runGoogleAuth(p, config);
} else {
@@ -34,6 +37,7 @@ export async function runSetup(configPath: string): Promise<void> {
const builder = await runFirstRunWizard(p);
saveConfig(configPath, builder, p);
const config = builder.build();
printOnboardingChecklist(p, config as Record<string, unknown>, configPath);
await printMinioExtractorSetupStatus(p, config as Record<string, unknown>);
await runGoogleAuth(p, config);
@@ -56,6 +60,7 @@ export async function runSetup(configPath: string): Promise<void> {
await runMenu(p, menuBuilder);
saveConfig(configPath, menuBuilder, p);
const config = menuBuilder.build();
printOnboardingChecklist(p, config as Record<string, unknown>, configPath);
await printMinioExtractorSetupStatus(p, config as Record<string, unknown>);
await runGoogleAuth(p, config);
}
@@ -73,6 +78,15 @@ function saveConfig(configPath: string, builder: ConfigBuilder, p: { println(msg
p.println(`✓ Config saved to ${configPath}`);
}
function printOnboardingChecklist(
p: { println(msg?: string): void },
config: Record<string, unknown>,
configPath: string,
): void {
p.println();
p.println(renderOnboardingChecklist(config as SetupConfig, { configPath }));
}
async function printMinioExtractorSetupStatus(
p: { println(msg?: string): void },
config: Record<string, unknown>,
+26 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { renderOperatorPackStatus, renderSummary } from './summary.js';
import { renderOnboardingChecklist, renderOperatorPackStatus, renderSummary } from './summary.js';
import type { SetupConfig } from './config.js';
describe('renderSummary', () => {
@@ -64,3 +64,28 @@ describe('renderSummary', () => {
expect(renderOperatorPackStatus(config)).toBe('Operator Pack: disabled');
});
});
describe('renderOnboardingChecklist', () => {
it('includes start command, webchat URL, and doctor hint', () => {
const config = {
server: { port: 19100, localhost: true },
} as unknown as SetupConfig;
const output = renderOnboardingChecklist(config, { configPath: '/tmp/flynn.yaml' });
expect(output).toContain('flynn start --config /tmp/flynn.yaml');
expect(output).toContain('http://localhost:19100/#/chat');
expect(output).toContain('flynn doctor');
});
it('includes channel-specific verification hints', () => {
const config = {
server: { port: 18800, localhost: true },
telegram: { bot_token: 'x', allowed_chat_ids: [1] },
slack: { bot_token: 'x', app_token: 'y', signing_secret: 'z', allowed_channel_ids: ['C1'] },
} as unknown as SetupConfig;
const output = renderOnboardingChecklist(config);
expect(output).toContain('Telegram: send `/status`');
expect(output).toContain('Slack: message the bot');
});
});
+30
View File
@@ -82,3 +82,33 @@ export function renderSummary(config: SetupConfig): string {
return lines.join('\n');
}
export function renderOnboardingChecklist(config: SetupConfig, opts?: { configPath?: string }): string {
const lines: string[] = [];
const startCmd = opts?.configPath
? `flynn start --config ${opts.configPath}`
: 'flynn start';
lines.push('Quick start checklist:');
lines.push(` 1. Start Flynn: ${startCmd}`);
const port = config.server?.port ?? 18800;
lines.push(` 2. Open WebChat: http://localhost:${port}/#/chat`);
lines.push(' 3. Send `/status` to verify model + gateway health');
if (config.telegram) {
lines.push(' 4. Telegram: send `/status` to your bot from an allowed chat ID');
}
if (config.discord) {
lines.push(' 4. Discord: mention the bot in an allowed server (`@bot /status`)');
}
if (config.slack) {
lines.push(' 4. Slack: message the bot in an allowed channel (`/status`)');
}
if (config.whatsapp) {
lines.push(' 4. WhatsApp: scan QR on first run, then send `/status`');
}
lines.push(' 5. Run `flynn doctor` if any channel test fails');
return lines.join('\n');
}