feat: add setup channel verification checklist output
This commit is contained in:
@@ -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
@@ -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",
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user