/**
 * `opensquid chat watch` — the inbox stream-source for the harness `Monitor`
 * tool (Track T-TR, TR.1). Resolves the active project's inbox JSONL and
 * streams NEW inbound messages to stdout, one formatted line per message.
 *
 * This is a NEW top-level `chat` verb group, distinct from `opensquid setup
 * chat` (the chat-agent wizard). The agent wraps it:
 *   Monitor({ command: "node dist/cli.js chat watch", persistent: true })
 * so each appended message → one in-chat event (no cron — see
 * docs/tasks/T-telegram-realtime.md L3 on why auto-start is an agent
 * convention, not a CLI side-effect).
 *
 * Umbrella resolution (T-CHAT-AS-TERMINAL CAT.1c): chat is keyed by UMBRELLA,
 * not per-cwd project_uuid. The cwd is resolved to its umbrella via
 * `loadChannelsConfig()` + `resolveUmbrellaForCwd` (longest-prefix over
 * `members`). `channels.json` is synthesized at the CAT.1d cutover, so an
 * absent config / unresolved umbrella exits with a clear message (graceful,
 * never throws). The `--umbrella` flag overrides resolution for tests + ops.
 *
 * Imports from: commander, ../../channels/routing.js, ../paths.js, ./watch.js.
 * Imported by: src/cli.ts (registers the `chat` parent verb).
 */
import { runMigration } from '../../channels/migrate.js';
import { loadChannelsConfig, resolveUmbrellaForCwd } from '../../channels/routing.js';
import { umbrellaInboxFile, umbrellaLiveSessionLease } from '../paths.js';
import { HEARTBEAT_MS, refreshLease, removeLease, resolveSessionId, writeLease, } from './live_session_lease.js';
import { startInboundWatcher } from './inbound_watch.js';
import { formatRow, watchInbox } from './watch.js';
export function registerChatWatch(program, deps = {}) {
    const watch = deps.watch ?? watchInbox;
    const startInbound = deps.startInbound ?? startInboundWatcher;
    const migrate = deps.migrate ?? runMigration;
    const chat = program.command('chat').description('Live chat inbound/outbound helpers.');
    // CAT.1d — `opensquid chat migrate [--force]`. One-shot legacy→umbrella
    // cutover: synthesize `~/.opensquid/channels.json` from the per-project
    // `chat-routing.json` + `projects.json`, then copy the per-uuid inbox rows
    // into the umbrella keyspace (non-destructive, idempotent). READ-ONLY w.r.t.
    // the legacy files. `--force` overwrites an existing channels.json.
    chat
        .command('migrate')
        .description('Synthesize channels.json from legacy per-project routing + copy inbox data.')
        .option('--force', 'overwrite an existing channels.json', false)
        .action(async (opts) => {
        const res = await migrate({ force: opts.force });
        const out = process.stdout;
        out.write(res.configWritten
            ? `channels.json written: ${res.configPath}\n`
            : `channels.json already present (use --force to overwrite): ${res.configPath}\n`);
        out.write(`umbrellas: ${String(res.config.umbrellas.length)}\n`);
        for (const u of res.config.umbrellas) {
            const rows = res.copied[u.id] ?? 0;
            out.write(`  ${u.id}: ${String(u.members.length)} member(s), ${String(rows)} inbox row(s) copied\n`);
        }
    });
    chat
        .command('watch')
        .description('Stream NEW inbound messages to stdout for the harness Monitor (no cron).')
        .option('--platform <name>', 'inbox platform (telegram, discord, …)', 'telegram')
        .option('--raw', 'emit raw JSONL rows instead of the formatted line', false)
        .option('--mentions-only', 'only emit rows where mentions_bot is true', false)
        .option('--umbrella <id>', 'override cwd→umbrella resolution')
        .action(async (opts) => {
        // CAT.1c: resolve the cwd to its UMBRELLA via channels.json (the single
        // authoritative routing source). `--umbrella` overrides for tests/ops.
        // Absent config / unresolved umbrella → exit cleanly (channels.json is
        // synthesized at the CAT.1d cutover; before then there is no inbox).
        let umbrellaId = opts.umbrella ?? null;
        if (umbrellaId === null) {
            const cfg = await loadChannelsConfig();
            umbrellaId = cfg === null ? null : resolveUmbrellaForCwd(cfg, process.cwd());
        }
        if (umbrellaId === null || umbrellaId === '') {
            process.stderr.write('chat watch: no umbrella for this cwd. Pass --umbrella, or add a ' +
                'matching `members` prefix to an umbrella in ~/.opensquid/channels.json ' +
                '(run `opensquid setup chat` to wire it).\n');
            process.exitCode = 1;
            return;
        }
        const leasePath = umbrellaLiveSessionLease(umbrellaId);
        // Claim the live-session lease so the always-on daemon stays silent while
        // this session handles the umbrella (T-DEL arbitration). Heartbeat keeps it
        // fresh; cleanup on exit + a SIGINT/SIGTERM handler remove it (staleness is
        // the fallback if we're killed ungracefully).
        await writeLease(leasePath, resolveSessionId());
        const heartbeat = setInterval(() => {
            void refreshLease(leasePath).catch(() => undefined);
        }, HEARTBEAT_MS);
        heartbeat.unref();
        const stopLease = async () => {
            clearInterval(heartbeat);
            process.removeListener('SIGINT', onSignal);
            process.removeListener('SIGTERM', onSignal);
            await removeLease(leasePath);
        };
        function onSignal() {
            void stopLease().finally(() => process.exit(0));
        }
        process.once('SIGINT', onSignal);
        process.once('SIGTERM', onSignal);
        // LL.3 (2026-05-30) — start the per-umbrella inbound watcher in
        // parallel with the existing stdout streamer. The watcher
        // dispatches inbound rows as `inbound_channel` events to the
        // live session's loaded packs; the streamer keeps the
        // `Monitor`-stdout contract intact for backward-compat with
        // existing chat watch consumers.
        const stopInbound = await startInbound();
        try {
            await watch({
                inboxFile: umbrellaInboxFile(umbrellaId, opts.platform),
                mentionsOnly: opts.mentionsOnly,
                format: opts.raw ? (r) => JSON.stringify(r) : formatRow,
                // Flush one line per message — Monitor reads stdout line-delimited.
                out: (line) => process.stdout.write(line + '\n'),
                onWarn: (message) => process.stderr.write(message + '\n'),
            });
        }
        finally {
            await stopInbound().catch(() => undefined);
            await stopLease();
        }
    });
    return chat;
}
//# sourceMappingURL=watch_cli.js.map