diff --git a/docs/plans/state.json b/docs/plans/state.json index 24030d3..c7a387b 100644 --- a/docs/plans/state.json +++ b/docs/plans/state.json @@ -193,12 +193,14 @@ "status": "completed", "date": "2026-02-16", "updated": "2026-02-16", - "summary": "Implemented operator-focused hardening and onboarding polish: added a setup Automation operator-pack path that preconfigures scheduled backups, heartbeat alerts, daily briefing, and default MinIO sync; added heartbeat notification throttling via `automation.heartbeat.notify_cooldown`; and added `flynn doctor --strict` to treat warnings as failures. Updated docs/default config examples accordingly.", + "summary": "Implemented operator-focused hardening and onboarding polish: added setup Operator Pack flows in both Automation menu and first-run wizard to preconfigure scheduled backups, heartbeat alerts, daily briefing, and default MinIO sync; added heartbeat notification throttling via `automation.heartbeat.notify_cooldown`; and added `flynn doctor --strict` to treat warnings as failures. Updated docs/default config examples and onboarding tests accordingly.", "files_modified": [ "src/cli/setup/config.ts", "src/cli/setup/config.test.ts", "src/cli/setup/automation.test.ts", "src/cli/setup/automation.ts", + "src/cli/setup/orchestrator.ts", + "src/cli/setup/integration.test.ts", "src/automation/heartbeat.ts", "src/automation/heartbeat.test.ts", "src/config/schema.ts", @@ -209,7 +211,7 @@ "README.md", "docs/plans/state.json" ], - "test_status": "pnpm test:run src/cli/setup/automation.test.ts src/cli/setup/config.test.ts src/automation/heartbeat.test.ts src/config/schema.test.ts src/cli/doctor.test.ts + pnpm typecheck passing" + "test_status": "pnpm test:run src/cli/setup/integration.test.ts src/cli/setup/automation.test.ts src/cli/setup/config.test.ts src/automation/heartbeat.test.ts src/config/schema.test.ts src/cli/doctor.test.ts + pnpm typecheck passing" }, "backup-session-summary-audit-trail": { "status": "completed", @@ -3495,7 +3497,7 @@ } }, "overall_progress": { - "total_test_count": 1865, + "total_test_count": 1866, "all_tests_passing": true, "p0_completion": "3/3 (100%)", "p1_completion": "4/4 (100%)", diff --git a/src/cli/setup/integration.test.ts b/src/cli/setup/integration.test.ts index 34abbad..2ec8c45 100644 --- a/src/cli/setup/integration.test.ts +++ b/src/cli/setup/integration.test.ts @@ -26,6 +26,7 @@ describe('first-run wizard integration', () => { 'n', // confirm: Configure a fast tier? (no) '', // ask: Gateway port (default) 'n', // confirm: Add a messaging channel? (no) + 'n', // confirm: Configure automation now? (no) ]); const p = createPrompter(rl); @@ -53,6 +54,7 @@ describe('first-run wizard integration', () => { '123:ABCdef', // password: Bot token '12345678', // ask: Allowed chat IDs 'n', // confirm: Add another channel? (no) + 'n', // confirm: Configure automation now? (no) ]); const p = createPrompter(rl); @@ -63,4 +65,38 @@ describe('first-run wizard integration', () => { expect(config.telegram!.bot_token).toBe('123:ABCdef'); expect(config.telegram!.allowed_chat_ids).toEqual([12345678]); }); + + it('can configure operator pack during first-run wizard', async () => { + const rl = mockReadline([ + '1', // choose: Anthropic + 'sk-ant-key', // password: API key + '', // ask: Model (default) + 'n', // confirm: Configure a fast tier? (no) + '', // ask: Gateway port (default) + 'y', // confirm: Add a messaging channel? (yes) + '1', // choose: Telegram + '123:ABCdef', // password: Bot token + '12345678', // ask: Allowed chat IDs + 'n', // confirm: Add another channel? (no) + 'y', // confirm: Configure automation now? (yes) + 'y', // confirm: Enable operator automation pack? (yes) + '', // ask: Backup cron schedule (default) + '', // ask: Daily briefing cron schedule (default) + '', // confirm: Include default MinIO sync task? (default yes) + 'n', // confirm: Enable cron scheduler? (no) + 'n', // confirm: Enable webhook receiver? (no) + 'n', // confirm: Configure Google services? (no) + ]); + const p = createPrompter(rl); + + const builder = await runFirstRunWizard(p); + const config = builder.build() as Record; + const backup = config.backup as Record; + const automation = config.automation as Record; + const heartbeat = automation.heartbeat as Record; + + expect(backup.enabled).toBe(true); + expect(backup.schedule).toBe('0 2 * * *'); + expect(heartbeat.enabled).toBe(true); + }); }); diff --git a/src/cli/setup/orchestrator.ts b/src/cli/setup/orchestrator.ts index 8ad26f5..61183d9 100644 --- a/src/cli/setup/orchestrator.ts +++ b/src/cli/setup/orchestrator.ts @@ -69,5 +69,12 @@ export async function runFirstRunWizard(p: Prompter): Promise { p.println(); await setupChannels(p, builder); + // Step 3: Optional automation pack + p.println(); + const configureAutomation = await p.confirm('Configure automation now (operator pack, cron, webhooks, Google services)?', false); + if (configureAutomation) { + await setupAutomation(p, builder); + } + return builder; }