feat(ops): add setup operator pack, heartbeat alert cooldown, and doctor strict mode
This commit is contained in:
@@ -57,6 +57,30 @@ const GOOGLE_SERVICES: GoogleService[] = [
|
||||
];
|
||||
|
||||
export async function setupAutomation(p: Prompter, builder: ConfigBuilder): Promise<void> {
|
||||
const enableOperatorPack = await p.confirm(
|
||||
'Enable operator automation pack (scheduled backups + heartbeat alerts + daily briefing + MinIO sync)?',
|
||||
false,
|
||||
);
|
||||
if (enableOperatorPack) {
|
||||
const config = builder.build();
|
||||
const telegramPeer = config.telegram?.allowed_chat_ids?.[0];
|
||||
const defaultOutputChannel = telegramPeer ? 'telegram' : 'webchat';
|
||||
const defaultOutputPeer = telegramPeer ? String(telegramPeer) : 'operator';
|
||||
|
||||
const backupSchedule = await p.ask('Backup cron schedule', '0 2 * * *');
|
||||
const dailyBriefingSchedule = await p.ask('Daily briefing cron schedule', '0 8 * * *');
|
||||
const enableMinioSync = await p.confirm('Include default MinIO sync task?', true);
|
||||
|
||||
builder.applyOperatorPack({
|
||||
outputChannel: defaultOutputChannel,
|
||||
outputPeer: defaultOutputPeer,
|
||||
backupSchedule,
|
||||
dailyBriefingSchedule,
|
||||
enableMinioSync,
|
||||
});
|
||||
p.println(`✓ Operator pack enabled (alerts routed to ${defaultOutputChannel}/${defaultOutputPeer})`);
|
||||
}
|
||||
|
||||
const cron = await p.confirm('Enable cron scheduler?', false);
|
||||
if (cron) {
|
||||
builder.setCronEnabled();
|
||||
|
||||
@@ -84,4 +84,23 @@ describe('ConfigBuilder', () => {
|
||||
const obj = builder.build();
|
||||
expect(obj.server.token).toBe('my-secret-token');
|
||||
});
|
||||
|
||||
it('applies operator automation pack defaults', () => {
|
||||
const builder = new ConfigBuilder();
|
||||
builder.applyOperatorPack({
|
||||
outputChannel: 'telegram',
|
||||
outputPeer: '123',
|
||||
backupSchedule: '0 2 * * *',
|
||||
dailyBriefingSchedule: '0 8 * * *',
|
||||
enableMinioSync: true,
|
||||
});
|
||||
|
||||
const obj = builder.build();
|
||||
expect(obj.backup?.enabled).toBe(true);
|
||||
expect(obj.backup?.schedule).toBe('0 2 * * *');
|
||||
expect(obj.backup?.run_on_start).toBe(true);
|
||||
expect((obj.automation as Record<string, unknown>)?.heartbeat).toBeDefined();
|
||||
expect((obj.automation as Record<string, unknown>)?.daily_briefing).toBeDefined();
|
||||
expect((obj.automation as Record<string, unknown>)?.minio_sync).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,9 +43,23 @@ export interface SetupConfig {
|
||||
gtasks?: { enabled?: boolean };
|
||||
heartbeat?: { enabled?: boolean };
|
||||
} & Record<string, unknown>;
|
||||
backup?: {
|
||||
enabled?: boolean;
|
||||
schedule?: string;
|
||||
run_on_start?: boolean;
|
||||
notify?: { channel: string; peer: string };
|
||||
} & Record<string, unknown>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface OperatorPackOptions {
|
||||
outputChannel: string;
|
||||
outputPeer: string;
|
||||
backupSchedule: string;
|
||||
dailyBriefingSchedule: string;
|
||||
enableMinioSync?: boolean;
|
||||
}
|
||||
|
||||
export class ConfigBuilder {
|
||||
private config: SetupConfig;
|
||||
|
||||
@@ -187,6 +201,54 @@ export class ConfigBuilder {
|
||||
this.config.automation = automation;
|
||||
}
|
||||
|
||||
applyOperatorPack(options: OperatorPackOptions): void {
|
||||
const automation = (this.config.automation ?? {}) as Record<string, unknown>;
|
||||
const backup = (this.config.backup ?? {}) as Record<string, unknown>;
|
||||
|
||||
backup.enabled = true;
|
||||
backup.schedule = options.backupSchedule;
|
||||
backup.run_on_start = true;
|
||||
backup.notify = { channel: options.outputChannel, peer: options.outputPeer };
|
||||
|
||||
automation.heartbeat = {
|
||||
enabled: true,
|
||||
notify: { channel: options.outputChannel, peer: options.outputPeer },
|
||||
interval: '5m',
|
||||
failure_threshold: 2,
|
||||
notify_cooldown: '30m',
|
||||
};
|
||||
|
||||
automation.daily_briefing = {
|
||||
enabled: true,
|
||||
schedule: options.dailyBriefingSchedule,
|
||||
output: { channel: options.outputChannel, peer: options.outputPeer },
|
||||
dedupe_per_local_day: true,
|
||||
model_tier: 'fast',
|
||||
};
|
||||
|
||||
if (options.enableMinioSync ?? true) {
|
||||
automation.minio_sync = {
|
||||
enabled: true,
|
||||
interval: '6h',
|
||||
run_on_start: true,
|
||||
notify: { channel: options.outputChannel, peer: options.outputPeer },
|
||||
tasks: [
|
||||
{
|
||||
prefix: 'knowledge/',
|
||||
namespace_base: 'global/knowledge/minio',
|
||||
mode: 'append',
|
||||
max_objects: 20,
|
||||
max_chars_per_object: 8000,
|
||||
force: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
this.config.automation = automation;
|
||||
this.config.backup = backup;
|
||||
}
|
||||
|
||||
build(): SetupConfig {
|
||||
return structuredClone(this.config) as SetupConfig;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user