feat(setup): surface operator-pack status and add operations runbook

This commit is contained in:
William Valentin
2026-02-16 15:30:38 -08:00
parent dc1c691ea5
commit 65efda3533
7 changed files with 145 additions and 6 deletions
+4 -2
View File
@@ -1,6 +1,6 @@
import type { Prompter } from './prompts.js';
import type { ConfigBuilder } from './config.js';
import { renderSummary } from './summary.js';
import { renderOperatorPackStatus, renderSummary } from './summary.js';
import { setupProviders } from './providers.js';
import { setupChannels } from './channels.js';
import { setupMemory } from './memory.js';
@@ -28,9 +28,11 @@ const SECTION_HANDLERS: Record<string, (p: Prompter, b: ConfigBuilder) => Promis
export async function runMenu(p: Prompter, builder: ConfigBuilder): Promise<void> {
while (true) {
const config = builder.build();
p.println();
p.println('Flynn Setup — Current Configuration');
p.println(renderSummary(builder.build()));
p.println(renderSummary(config));
p.println(` ${renderOperatorPackStatus(config)}`);
p.println();
p.println('What would you like to configure?');
for (let i = 0; i < MENU_OPTIONS.length; i++) {
+40 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { renderSummary } from './summary.js';
import { renderOperatorPackStatus, renderSummary } from './summary.js';
import type { SetupConfig } from './config.js';
describe('renderSummary', () => {
@@ -24,4 +24,43 @@ describe('renderSummary', () => {
expect(output).toContain('Automation: heartbeat, daily-briefing, minio-sync');
expect(output).toContain('Backup: enabled (cron 0 2 * * *)');
});
it('renders compact operator pack status line with routing when enabled', () => {
const config = {
models: {
default: { provider: 'anthropic', model: 'claude-sonnet' },
},
server: { port: 18800, localhost: true },
automation: {
heartbeat: {
enabled: true,
notify: { channel: 'telegram', peer: '123' },
},
daily_briefing: { enabled: true },
},
backup: {
enabled: true,
notify: { channel: 'telegram', peer: '123' },
},
} as unknown as SetupConfig;
expect(renderOperatorPackStatus(config)).toBe('Operator Pack: enabled (telegram/123)');
});
it('renders compact operator pack status line as disabled when partial config', () => {
const config = {
models: {
default: { provider: 'anthropic', model: 'claude-sonnet' },
},
server: { port: 18800, localhost: true },
automation: {
heartbeat: { enabled: true },
},
backup: {
enabled: true,
},
} as unknown as SetupConfig;
expect(renderOperatorPackStatus(config)).toBe('Operator Pack: disabled');
});
});
+21
View File
@@ -1,5 +1,26 @@
import type { SetupConfig } from './config.js';
export function renderOperatorPackStatus(config: SetupConfig): string {
const automation = config.automation ?? {};
const backup = config.backup;
const enabled = Boolean(
backup?.enabled
&& automation.heartbeat?.enabled
&& automation.daily_briefing?.enabled,
);
if (!enabled) {
return 'Operator Pack: disabled';
}
const notify = backup?.notify ?? (automation.heartbeat as { notify?: { channel?: string; peer?: string } } | undefined)?.notify;
if (notify?.channel && notify?.peer) {
return `Operator Pack: enabled (${notify.channel}/${notify.peer})`;
}
return 'Operator Pack: enabled';
}
export function renderSummary(config: SetupConfig): string {
const lines: string[] = [];