linear-cmd
Version:
A GitHub CLI-like tool for Linear - manage issues, accounts, and more
231 lines (230 loc) • 8.67 kB
JavaScript
import { accessSync, constants, existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
import { colors } from '../../lib/colors.js';
import { logger } from '../../lib/logger.js';
import { generateBashCompletion, generateZshCompletion } from '../../schemas/generators/completion-generator.js';
import { detectShell as detectShellUtil, isWindows } from '../../utils/shell-utils.js';
const ZSH_COMPLETION_SCRIPT = generateZshCompletion();
const BASH_COMPLETION_SCRIPT = generateBashCompletion();
function findFirstWritableDir(possibleDirs) {
for (const dir of possibleDirs) {
if (existsSync(dir)) {
try {
accessSync(dir, constants.W_OK);
return dir;
}
catch { }
}
}
return null;
}
export async function clearZshCompletionCache() {
const homeDir = homedir();
try {
const files = readdirSync(homeDir);
for (const file of files) {
if (file.startsWith('.zcompdump')) {
const fullPath = join(homeDir, file);
try {
unlinkSync(fullPath);
}
catch { }
}
}
const cacheDirs = [join(homeDir, '.zsh_cache'), join(homeDir, '.cache', 'zsh'), join(homeDir, '.zcompcache')];
for (const cacheDir of cacheDirs) {
if (existsSync(cacheDir)) {
try {
const cacheFiles = readdirSync(cacheDir);
for (const file of cacheFiles) {
if (file.includes('compdump') || file.includes('_linear')) {
try {
unlinkSync(join(cacheDir, file));
}
catch { }
}
}
}
catch { }
}
}
}
catch { }
}
export async function installZshCompletion(silent = false) {
const homeDir = homedir();
const possibleDirs = isWindows()
? [join(homeDir, '.zsh', 'completions'), join(homeDir, '.config', 'zsh', 'completions')]
: [
join(homeDir, '.oh-my-zsh', 'completions'),
join(homeDir, '.zsh', 'completions'),
join(homeDir, '.config', 'zsh', 'completions'),
join(homeDir, '.local', 'share', 'zsh', 'site-functions'),
'/usr/local/share/zsh/site-functions'
];
let targetDir = findFirstWritableDir(possibleDirs);
if (!targetDir) {
targetDir = join(homeDir, '.zsh', 'completions');
mkdirSync(targetDir, { recursive: true });
}
const completionFile = join(targetDir, '_linear');
writeFileSync(completionFile, ZSH_COMPLETION_SCRIPT);
if (!silent) {
logger.success(`✅ Zsh completion installed to ${completionFile}`);
logger.info('');
logger.info('To activate completion, add this to your ~/.zshrc:');
logger.info(colors.cyan(` fpath=(${targetDir} $fpath)`));
logger.info(colors.cyan(' autoload -U compinit && compinit'));
logger.info('');
logger.info('Then restart your shell or run:');
logger.info(colors.cyan(' source ~/.zshrc'));
try {
const zshrc = join(homeDir, '.zshrc');
if (existsSync(zshrc)) {
const zshrcContent = readFileSync(zshrc, 'utf8');
if (!zshrcContent.includes(targetDir)) {
logger.info('');
logger.warning('⚠️ Remember to add the fpath line to your ~/.zshrc for autocompletion to work!');
}
}
}
catch { }
}
}
export async function installBashCompletion(silent = false) {
const homeDir = homedir();
const possibleDirs = isWindows()
? [join(homeDir, '.bash_completion.d'), join(homeDir, '.local', 'share', 'bash-completion', 'completions')]
: [
join(homeDir, '.bash_completion.d'),
join(homeDir, '.local', 'share', 'bash-completion', 'completions'),
'/usr/local/etc/bash_completion.d',
'/etc/bash_completion.d'
];
let targetDir = findFirstWritableDir(possibleDirs);
if (!targetDir) {
targetDir = join(homeDir, '.bash_completion.d');
mkdirSync(targetDir, { recursive: true });
}
const completionFile = join(targetDir, 'linear');
writeFileSync(completionFile, BASH_COMPLETION_SCRIPT);
if (!silent) {
logger.success(`✅ Bash completion installed to ${completionFile}`);
logger.info('');
logger.info('To activate completion, add this to your ~/.bashrc:');
logger.info(colors.cyan(` source ${completionFile}`));
logger.info('');
logger.info('Then restart your shell or run:');
logger.info(colors.cyan(' source ~/.bashrc'));
}
}
export async function uninstallZshCompletion(silent = false) {
const homeDir = homedir();
const possibleDirs = isWindows()
? [join(homeDir, '.zsh', 'completions'), join(homeDir, '.config', 'zsh', 'completions')]
: [
join(homeDir, '.oh-my-zsh', 'completions'),
join(homeDir, '.zsh', 'completions'),
join(homeDir, '.config', 'zsh', 'completions'),
join(homeDir, '.local', 'share', 'zsh', 'site-functions'),
'/usr/local/share/zsh/site-functions'
];
let foundFiles = 0;
for (const dir of possibleDirs) {
const completionFile = join(dir, '_linear');
if (existsSync(completionFile)) {
try {
unlinkSync(completionFile);
foundFiles++;
if (!silent) {
logger.success(`✅ Removed completion file: ${completionFile}`);
}
}
catch (error) {
if (!silent) {
logger.warning(`⚠️ Could not remove ${completionFile}: ${error}`);
}
}
}
}
await clearZshCompletionCache();
if (!silent) {
if (foundFiles === 0) {
logger.warning('⚠️ No completion files found');
}
else {
logger.info('');
logger.success('✅ Zsh completion uninstalled successfully');
logger.info('');
logger.info('Restart your shell or run:');
logger.info(colors.cyan(' source ~/.zshrc'));
}
}
}
export async function uninstallBashCompletion(silent = false) {
const homeDir = homedir();
const possibleDirs = isWindows()
? [join(homeDir, '.bash_completion.d'), join(homeDir, '.local', 'share', 'bash-completion', 'completions')]
: [
join(homeDir, '.bash_completion.d'),
join(homeDir, '.local', 'share', 'bash-completion', 'completions'),
'/usr/local/etc/bash_completion.d',
'/etc/bash_completion.d'
];
let foundFiles = 0;
for (const dir of possibleDirs) {
const completionFile = join(dir, 'linear');
if (existsSync(completionFile)) {
try {
unlinkSync(completionFile);
foundFiles++;
if (!silent) {
logger.success(`✅ Removed completion file: ${completionFile}`);
}
}
catch (error) {
if (!silent) {
logger.warning(`⚠️ Could not remove ${completionFile}: ${error}`);
}
}
}
}
if (!silent) {
if (foundFiles === 0) {
logger.warning('⚠️ No completion files found');
}
else {
logger.info('');
logger.success('✅ Bash completion uninstalled successfully');
logger.info('');
logger.info('Restart your shell or run:');
logger.info(colors.cyan(' source ~/.bashrc'));
}
}
}
export function detectShell() {
return detectShellUtil();
}
export async function reinstallCompletionSilently(isInstalled) {
if (!isInstalled) {
return false;
}
const shell = detectShellUtil();
try {
switch (shell) {
case 'zsh':
await installZshCompletion(true);
await clearZshCompletionCache();
return true;
case 'bash':
await installBashCompletion(true);
return true;
default:
return false;
}
}
catch {
return false;
}
}