linear-cmd
Version:
A GitHub CLI-like tool for Linear - manage issues, accounts, and more
188 lines (187 loc) • 6.29 kB
JavaScript
import { existsSync, mkdirSync } from 'node:fs';
import { getConfigPaths } from '../constants.js';
import { linearConfigSchema, userMetadataSchema } from '../types/local.js';
import { readJson5, writeJson5 } from '../utils/json-utils.js';
export class ConfigManager {
userMetadata = null;
config = null;
constructor() {
this.ensureConfigDirectory();
this.initializeUserMetadata();
}
ensureConfigDirectory() {
const configPaths = getConfigPaths();
if (!existsSync(configPaths.configDir)) {
mkdirSync(configPaths.configDir, { recursive: true });
}
}
initializeUserMetadata() {
const configPaths = getConfigPaths();
if (!existsSync(configPaths.userMetadataFile)) {
this.createDefaultUserMetadata();
}
this.loadUserMetadata();
}
createDefaultUserMetadata() {
const configPaths = getConfigPaths();
const defaultMetadata = {
config_path: configPaths.defaultConfigFile
};
writeJson5(configPaths.userMetadataFile, defaultMetadata);
}
loadUserMetadata() {
const configPaths = getConfigPaths();
try {
const data = readJson5(configPaths.userMetadataFile);
const validated = userMetadataSchema.parse(data);
this.userMetadata = validated;
}
catch (error) {
throw new Error(`Failed to load user metadata: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
getConfigPath() {
if (!this.userMetadata) {
throw new Error('User metadata not loaded');
}
return this.userMetadata.config_path;
}
loadConfig(forceReload = false) {
if (this.config && !forceReload) {
return this.config;
}
const configPath = this.getConfigPath();
if (!existsSync(configPath)) {
this.createDefaultConfig();
}
try {
const data = readJson5(configPath);
const validated = linearConfigSchema.parse(data);
this.config = validated;
return this.config;
}
catch (error) {
throw new Error(`Failed to load config: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
createDefaultConfig() {
const defaultConfig = {
accounts: {}
};
const configPath = this.getConfigPath();
writeJson5(configPath, defaultConfig);
}
saveConfig() {
if (!this.config) {
throw new Error('No config to save');
}
const configPath = this.getConfigPath();
writeJson5(configPath, this.config);
}
// Public API Methods
async addAccount(name, apiKey, teamId) {
const config = this.loadConfig();
if (config.accounts[name]) {
throw new Error(`Account '${name}' already exists`);
}
const account = {
name,
api_key: apiKey,
team_id: teamId
};
config.accounts[name] = account;
const accountCount = Object.keys(config.accounts).length;
if (!config.activeAccountName || accountCount === 1) {
config.activeAccountName = name;
}
this.saveConfig();
}
async removeAccount(name) {
const config = this.loadConfig();
if (!config.accounts[name]) {
throw new Error(`Account '${name}' not found`);
}
delete config.accounts[name];
if (config.activeAccountName === name) {
const remainingAccounts = Object.keys(config.accounts);
config.activeAccountName = remainingAccounts.length > 0 ? remainingAccounts[0] : undefined;
}
this.saveConfig();
}
getActiveAccount() {
const config = this.loadConfig(true);
if (!config.activeAccountName) {
return null;
}
return config.accounts[config.activeAccountName] || null;
}
getActiveAccountName() {
const config = this.loadConfig(true);
return config.activeAccountName || null;
}
setActiveAccount(name) {
const config = this.loadConfig();
if (!config.accounts[name]) {
return false;
}
config.activeAccountName = name;
this.saveConfig();
return true;
}
getAllAccounts() {
const config = this.loadConfig(true);
return Object.values(config.accounts);
}
getAccount(name) {
const config = this.loadConfig(true);
return config.accounts[name] || null;
}
listAccounts() {
const config = this.loadConfig(true);
return Object.entries(config.accounts).map(([name, account]) => ({
name,
teamId: account.team_id
}));
}
updateAccountApiKey(name, apiKey) {
const config = this.loadConfig();
if (!config.accounts[name]) {
throw new Error(`Account '${name}' not found`);
}
config.accounts[name].api_key = apiKey;
this.saveConfig();
}
findAccountByWorkspace(workspace) {
const config = this.loadConfig(true);
const accounts = Object.values(config.accounts);
return accounts.find((a) => a.workspaces?.includes(workspace)) || null;
}
async updateAccountWorkspaces(accountId, workspaces) {
const config = this.loadConfig();
if (!config.accounts[accountId]) {
throw new Error(`Account '${accountId}' not found`);
}
config.accounts[accountId].workspaces = workspaces;
this.saveConfig();
}
markCompletionInstalled() {
const config = this.loadConfig();
if (!config.settings) {
config.settings = {};
}
config.settings.completion_installed = true;
this.saveConfig();
}
markCompletionUninstalled() {
const config = this.loadConfig();
if (!config.settings) {
config.settings = {};
}
config.settings.completion_installed = false;
this.saveConfig();
}
isCompletionInstalled() {
const config = this.loadConfig();
return config.settings?.completion_installed === true;
}
}