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
+2
View File
@@ -78,6 +78,8 @@ Flynn provides a full CLI via the `flynn` binary (or `npx tsx src/cli/index.ts`
| `flynn gcal-auth` | Authenticate with Google Calendar via OAuth2 |
| `flynn skills` | List/install/manage skills |
`flynn setup` / `flynn onboard` now print a post-save channel verification checklist (start command, WebChat URL, `/status` smoke test, and channel-specific validation hints).
### Examples
```bash
+16 -2
View File
@@ -5349,10 +5349,24 @@
"docs/plans/state.json"
],
"test_status": "pnpm test:run src/gateway/server.test.ts src/config/schema.test.ts + pnpm typecheck passing"
},
"guided-onboarding-channel-verification-tier-b1": {
"status": "completed",
"date": "2026-02-18",
"updated": "2026-02-18",
"summary": "Improved Tier B1 onboarding speed by adding a post-save quick-start verification checklist to `flynn setup`/`flynn onboard`, including start command, WebChat URL, `/status` smoke test, and channel-specific validation hints for configured messaging adapters.",
"files_modified": [
"src/cli/setup.ts",
"src/cli/setup/summary.ts",
"src/cli/setup/summary.test.ts",
"README.md",
"docs/plans/state.json"
],
"test_status": "pnpm test:run src/cli/setup/summary.test.ts src/cli/setup/channels.test.ts src/cli/setup/integration.test.ts + pnpm typecheck passing"
}
},
"overall_progress": {
"total_test_count": 1913,
"total_test_count": 1918,
"all_tests_passing": true,
"p0_completion": "3/3 (100%)",
"p1_completion": "4/4 (100%)",
@@ -5372,7 +5386,7 @@
"gmail_auth_cli": "flynn gmail-auth command implemented with OAuth2 flow, doctor check, config routed to Telegram",
"native_audio_support": "completed — smart routing for native audio (Gemini/OpenAI/GitHub) vs Whisper transcription fallback",
"remaining_phases_completion": "Phase 1: 3/3 (100%) — context levels, command registry, memory structure. Phase 2: 3/3 (100%) — component registry, confidence routing, history index. Phase 3: 2/2 (100%) — adaptive memory/compaction, truthfulness/autonomy hardening",
"next_up": "Implement Tier B1 guided onboarding improvement"
"next_up": "Implement Tier B5 streaming chunking quality parity checks"
},
"soul_md_and_cron_create": {
"date": "2026-02-11",
+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');
}