/** * Phase 5 of openspec/specs/management-as-module/spec.md — confirm `celilo system init` * surfaces a deprecation banner pointing at the new paths * (bootstrap.sh + `system apply-config`), and that * CELILO_SUPPRESS_DEPRECATION=1 silences it. * * The banner is operator-facing UX; we verify the contract rather than * pin specific wording. */ import { afterEach, beforeEach, describe, expect, test } from 'bun:test'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { resetTestDbPath } from '../../test-utils/db-path'; import { handleSystemInit } from './system-init'; interface CapturedStream { out: string[]; restore: () => void; } function captureStderr(): CapturedStream { const original = console.warn; const captured: string[] = []; console.warn = (...args: unknown[]) => { captured.push(args.map(String).join(' ')); }; return { out: captured, restore: () => { console.warn = original; }, }; } describe('celilo system init deprecation banner', () => { let tmpDir: string; let savedSuppress: string | undefined; beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), 'celilo-deprecation-test-')); savedSuppress = process.env.CELILO_SUPPRESS_DEPRECATION; process.env.CELILO_DB_PATH = join(tmpDir, 'init.db'); delete process.env.CELILO_SUPPRESS_DEPRECATION; }); afterEach(() => { // Never restore the previous value: it may be another suite's temp // database (or, worse, unset — which sends the next var-less reader to // the operator's real celilo.db). The scratch path is the neutral state // (celilo#1315). resetTestDbPath(); process.env.CELILO_SUPPRESS_DEPRECATION = savedSuppress; rmSync(tmpDir, { recursive: true, force: true }); }); test('prints a deprecation banner on stderr by default', async () => { const captured = captureStderr(); try { await handleSystemInit([], { 'accept-defaults': true }); } finally { captured.restore(); } const all = captured.out.join('\n'); expect(all).toContain('deprecated'); expect(all).toContain('bootstrap.sh'); expect(all).toContain('apply-config'); }); test('CELILO_SUPPRESS_DEPRECATION=1 silences the banner', async () => { process.env.CELILO_SUPPRESS_DEPRECATION = '1'; const captured = captureStderr(); try { await handleSystemInit([], { 'accept-defaults': true }); } finally { captured.restore(); } const all = captured.out.join('\n'); expect(all).not.toContain('deprecated'); }); test('the command still executes successfully when the banner fires', async () => { const captured = captureStderr(); let result: Awaited>; try { result = await handleSystemInit([], { 'accept-defaults': true }); } finally { captured.restore(); } expect(result.success).toBe(true); }); });