diff --git a/README.md b/README.md index cef55fe..55bad64 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/plans/state.json b/docs/plans/state.json index c4f3632..15131ad 100644 --- a/docs/plans/state.json +++ b/docs/plans/state.json @@ -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", diff --git a/src/cli/setup.ts b/src/cli/setup.ts index 0f678a3..a0c9fd5 100644 --- a/src/cli/setup.ts +++ b/src/cli/setup.ts @@ -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 { const rl = createInterface({ input: process.stdin, output: process.stdout }); @@ -27,6 +29,7 @@ export async function runSetup(configPath: string): Promise { await runMenu(p, builder); saveConfig(configPath, builder, p); const config = builder.build(); + printOnboardingChecklist(p, config as Record, configPath); await printMinioExtractorSetupStatus(p, config as Record); await runGoogleAuth(p, config); } else { @@ -34,6 +37,7 @@ export async function runSetup(configPath: string): Promise { const builder = await runFirstRunWizard(p); saveConfig(configPath, builder, p); const config = builder.build(); + printOnboardingChecklist(p, config as Record, configPath); await printMinioExtractorSetupStatus(p, config as Record); await runGoogleAuth(p, config); @@ -56,6 +60,7 @@ export async function runSetup(configPath: string): Promise { await runMenu(p, menuBuilder); saveConfig(configPath, menuBuilder, p); const config = menuBuilder.build(); + printOnboardingChecklist(p, config as Record, configPath); await printMinioExtractorSetupStatus(p, config as Record); 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, + configPath: string, +): void { + p.println(); + p.println(renderOnboardingChecklist(config as SetupConfig, { configPath })); +} + async function printMinioExtractorSetupStatus( p: { println(msg?: string): void }, config: Record, diff --git a/src/cli/setup/summary.test.ts b/src/cli/setup/summary.test.ts index 2da1bf5..fcb6b9f 100644 --- a/src/cli/setup/summary.test.ts +++ b/src/cli/setup/summary.test.ts @@ -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'); + }); +}); diff --git a/src/cli/setup/summary.ts b/src/cli/setup/summary.ts index 8713f5a..80af12a 100644 --- a/src/cli/setup/summary.ts +++ b/src/cli/setup/summary.ts @@ -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'); +}