UNPKG

consortium

Version:

Remote control and session sharing CLI for AI coding agents

141 lines (125 loc) 5.32 kB
#!/usr/bin/env node /** * consortium-local — deprecated alias for `consortium code`. * * Historically this was the primary entry point for launching Consortium Code * locally. The main `consortium` binary now ships an interactive TUI as its * default no-args action, and `consortium code` is the supported direct * launcher, so this shim exists only to guide existing users across. * * Behavior: * - Prints a visible, multi-line deprecation banner to stderr (ANSI-colored * only when stderr is a TTY — same postinstall-safe pattern used in * scripts/verify-platform.cjs, no chalk dependency). * - Execs `consortium code` with the same argv, stdio inheritance, and * propagates the child's exit code. * - Honors CONSORTIUM_HIDE_DEPRECATION_WARNING=1 as a silent escape hatch * for automation / scripts that can't tolerate the extra output. * * This alias will be removed in the next major release. */ import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; // --- ANSI helpers (no chalk — this file runs without devDeps guaranteed) ---- const isTTY = process.stderr.isTTY === true; const ansi = (code, text) => (isTTY ? `\u001b[${code}m${text}\u001b[0m` : text); const bold = (t) => ansi('1', t); const yellow = (t) => ansi('33', t); const dim = (t) => ansi('2', t); const MIGRATION_URL = 'https://github.com/ConsortiumAI/consortium-cli#migrating-from-consortium-local'; /** * Strip ANSI SGR escape sequences for visible-width calculations. ANSI bytes * are part of the string's .length but render as zero columns, so naive * padding breaks box alignment whenever bold/yellow/dim wrap a segment. */ function visibleLength(s) { // Matches CSI-style SGR sequences like "\u001b[1m" / "\u001b[33m" / "\u001b[0m". // eslint-disable-next-line no-control-regex return s.replace(/\u001b\[[0-9;]*m/g, '').length; } /** * Print the multi-line deprecation banner to stderr. Rendered with box-drawing * characters and ANSI color when the stream is a TTY; falls back to plain text * otherwise so piped output / CI logs stay readable. */ function printDeprecationBanner() { const W = 84; // inner width of the box — fits the migration URL on one line const pad = (text, width) => { const visible = visibleLength(text); if (visible >= width) return text; return text + ' '.repeat(width - visible); }; const top = '\u250c' + '\u2500'.repeat(W) + '\u2510'; const bot = '\u2514' + '\u2500'.repeat(W) + '\u2518'; const sep = (content) => '\u2502' + pad(content, W) + '\u2502'; const lines = [ top, sep(' ' + bold(yellow('DEPRECATED')) + ' `consortium-local` is deprecated.'), sep(''), sep(' Run `consortium code` to launch Consortium Code directly,'), sep(' or `consortium` to open the interactive menu.'), sep(''), sep(' This alias will be removed in the next major release.'), sep(' Migration guide:'), sep(' ' + dim(MIGRATION_URL)), bot, '', ]; process.stderr.write(lines.join('\n') + '\n'); } function main() { const hideWarning = process.env.CONSORTIUM_HIDE_DEPRECATION_WARNING === '1'; if (!hideWarning) { printDeprecationBanner(); } // Resolve sibling `consortium.mjs` so we always hit the same CLI build, // regardless of PATH ordering or global install location. const here = dirname(fileURLToPath(import.meta.url)); const consortiumBin = join(here, 'consortium.mjs'); // If the first arg is a recognized top-level subcommand, forward it // directly to `consortium` instead of prepending `code`. Without this, // commands like `consortium-local auth login --force` were rewritten to // `consortium code auth login --force` — the Code launcher silently // ignored the unknown flags, skipped re-auth, and dropped users into the // Code TUI. The default case (no subcommand, or args meant for Code) // still routes through `consortium code` to preserve the historical // alias behavior. const argv = process.argv.slice(2); const TOP_LEVEL_SUBCOMMANDS = new Set([ 'auth', 'doctor', 'connect', 'orgs', 'switch-org', 'whoami', 'deployments', 'codex', 'gemini', 'code', 'opencode', 'logout', 'notify', 'daemon', 'register-machine', 'claude', 'help', '--help', '-h', '--version', '-v', ]); const first = argv[0]; const passthrough = first && TOP_LEVEL_SUBCOMMANDS.has(first); const childArgs = passthrough ? [consortiumBin, ...argv] : [consortiumBin, 'code', ...argv]; // Inherit stdio + env so the child is indistinguishable from a direct // `consortium` invocation. spawnSync (vs execFileSync) lets us // propagate the exact exit code including signal-kill cases. const result = spawnSync( process.execPath, childArgs, { stdio: 'inherit', env: process.env }, ); if (result.error) { process.stderr.write( `consortium-local: failed to exec \`consortium code\`: ${result.error.message}\n`, ); process.exit(1); } if (typeof result.status === 'number') { process.exit(result.status); } if (result.signal) { // Child died to a signal — surface that as a non-zero exit so callers // can detect abnormal termination. process.exit(128); } process.exit(0); } main();