From 666e5f336a9fbf1265af4700a1a5aab979ed3c24 Mon Sep 17 00:00:00 2001 From: Thibault You Date: Mon, 21 Oct 2024 00:27:24 +0200 Subject: [PATCH] :bug: fix(env): Fix config file cache --- .github/workflows/update_views.yml | 2 +- .gitignore | 3 ++ src/app/utils/prompt_operations.ts | 2 +- src/cli/commands/menu.command.ts | 4 +- src/cli/index.ts | 16 +++++--- src/cli/utils/conversation.util.ts | 2 - src/cli/utils/database.util.ts | 4 +- src/cli/utils/prompt.util.ts | 8 ++-- src/shared/config/config.constants.ts | 4 +- src/shared/config/index.ts | 54 ++++++++++++++++++++++----- src/shared/utils/anthropic_client.ts | 4 +- 11 files changed, 72 insertions(+), 31 deletions(-) diff --git a/.github/workflows/update_views.yml b/.github/workflows/update_views.yml index 996cba4..4b25df6 100644 --- a/.github/workflows/update_views.yml +++ b/.github/workflows/update_views.yml @@ -68,7 +68,7 @@ jobs: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} FORCE_REGENERATE: ${{ env.FORCE_REGENERATE }} - CLI_ENV: github_actions + CLI_ENV: ci run: npm run generate-metadata - name: Update views diff --git a/.gitignore b/.gitignore index 22e1362..7f13a33 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ archive/ # Ignore local database *.sqlite +# Ignore macOS files +.DS_Store + # Ignore local temporary files z_diff_output.txt z_dir2prompt_output.txt \ No newline at end of file diff --git a/src/app/utils/prompt_operations.ts b/src/app/utils/prompt_operations.ts index 437763e..cbce937 100644 --- a/src/app/utils/prompt_operations.ts +++ b/src/app/utils/prompt_operations.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { Metadata } from '../../shared/types'; -import { readFileContent, readDirectory, isDirectory } from '../../shared/utils/file_operations'; +import { isDirectory, readDirectory, readFileContent } from '../../shared/utils/file_operations'; import logger from '../../shared/utils/logger'; import { processPromptContent } from '../../shared/utils/prompt_operations'; import { appConfig } from '../config/app.config'; diff --git a/src/cli/commands/menu.command.ts b/src/cli/commands/menu.command.ts index bf9a194..0d82fce 100644 --- a/src/cli/commands/menu.command.ts +++ b/src/cli/commands/menu.command.ts @@ -3,7 +3,7 @@ import { Command } from 'commander'; import { BaseCommand } from './base.command'; import { getConfig } from '../../shared/config'; -import { hasPrompts, hasFragments } from '../utils/content.util'; +import { hasFragments, hasPrompts } from '../utils/content.util'; type MenuAction = 'sync' | 'prompts' | 'fragments' | 'settings' | 'env' | 'back'; @@ -32,7 +32,7 @@ class MenuCommand extends BaseCommand { { name: 'Settings', value: 'settings' } ); - console.clear(); + // console.clear(); const action = await this.showMenu( `${chalk.reset(chalk.italic(chalk.cyan('Want to manage AI prompts with ease ?')))} diff --git a/src/cli/index.ts b/src/cli/index.ts index 2da7ca0..54b254f 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,10 +1,9 @@ #!/usr/bin/env node -process.env.PROMPT_LIBRARY_ENV = 'cli'; - import { input } from '@inquirer/prompts'; import { Command } from 'commander'; import dotenv from 'dotenv'; +import { getConfigValue, setConfig } from '../shared/config'; import configCommand from './commands/config.command'; import envCommand from './commands/env.command'; import executeCommand from './commands/execute.command'; @@ -15,18 +14,23 @@ import promptsCommand from './commands/prompts.command'; import settingsCommand from './commands/settings.command'; import syncCommand from './commands/sync.command'; import { initDatabase } from './utils/database.util'; -import { getConfig, setConfig } from '../shared/config'; + +process.env.CLI_ENV = 'cli'; dotenv.config(); async function ensureApiKey(): Promise { - const config = getConfig(); + let apiKey = getConfigValue('ANTHROPIC_API_KEY'); - if (!config.ANTHROPIC_API_KEY) { + if (!apiKey) { console.log('ANTHROPIC_API_KEY is not set.'); - const apiKey = await input({ message: 'Please enter your Anthropic API key:' }); + apiKey = await input({ message: 'Please enter your Anthropic API key:' }); setConfig('ANTHROPIC_API_KEY', apiKey); } + + if (!getConfigValue('ANTHROPIC_API_KEY')) { + throw new Error('Failed to set ANTHROPIC_API_KEY'); + } } async function main(): Promise { diff --git a/src/cli/utils/conversation.util.ts b/src/cli/utils/conversation.util.ts index 103f875..d97c47c 100644 --- a/src/cli/utils/conversation.util.ts +++ b/src/cli/utils/conversation.util.ts @@ -1,5 +1,3 @@ -// Updated ConversationManager class - import { processCliPromptContent, resolveCliInputs } from './prompt.cli.util'; import { getPromptFiles } from './prompt.util'; import { ApiResult } from '../../shared/types'; diff --git a/src/cli/utils/database.util.ts b/src/cli/utils/database.util.ts index 7fdbe5b..cf41072 100644 --- a/src/cli/utils/database.util.ts +++ b/src/cli/utils/database.util.ts @@ -6,11 +6,11 @@ import yaml from 'js-yaml'; import NodeCache from 'node-cache'; import sqlite3, { RunResult } from 'sqlite3'; -import { handleError, AppError } from './error.util'; +import { AppError, handleError } from './error.util'; import { createPrompt } from './prompt.util'; import { commonConfig } from '../../shared/config/common.config'; import { ApiResult, CategoryItem, Metadata, Prompt, Variable } from '../../shared/types'; -import { readDirectory, fileExists, readFileContent } from '../../shared/utils/file_operations'; +import { fileExists, readDirectory, readFileContent } from '../../shared/utils/file_operations'; import logger from '../../shared/utils/logger'; import { cliConfig } from '../config/cli.config'; diff --git a/src/cli/utils/prompt.util.ts b/src/cli/utils/prompt.util.ts index 0a0842f..1c96d27 100644 --- a/src/cli/utils/prompt.util.ts +++ b/src/cli/utils/prompt.util.ts @@ -1,11 +1,11 @@ import chalk from 'chalk'; -import { runAsync, getAsync, allAsync } from './database.util'; +import { allAsync, getAsync, runAsync } from './database.util'; import { readEnvVars } from './env.util'; import { getPromptMetadata } from './metadata.util'; -import { Metadata, Prompt, ApiResult, Variable } from '../../shared/types'; +import { ApiResult, Metadata, Prompt, Variable } from '../../shared/types'; import { processPromptContent } from '../../shared/utils/prompt_operations'; -import { formatTitleCase, formatSnakeCase } from '../../shared/utils/string_formatter'; +import { formatSnakeCase, formatTitleCase } from '../../shared/utils/string_formatter'; export async function createPrompt(metadata: Metadata, content: string): Promise> { try { @@ -126,7 +126,7 @@ export async function getPromptFiles( } export async function viewPromptDetails(details: Prompt & { variables: Variable[] }, isExecute = false): Promise { - console.clear(); + // console.clear(); console.log(chalk.cyan('Prompt:'), details.title); console.log(`\n${details.description || ''}`); console.log(chalk.cyan('\nCategory:'), formatTitleCase(details.primary_category)); diff --git a/src/shared/config/config.constants.ts b/src/shared/config/config.constants.ts index 1abde57..1313548 100644 --- a/src/shared/config/config.constants.ts +++ b/src/shared/config/config.constants.ts @@ -1,7 +1,9 @@ import * as os from 'os'; import * as path from 'path'; -export const isCliEnvironment = process.env.PROMPT_LIBRARY_ENV === 'cli'; +import { commonConfig } from './common.config'; + +export const isCliEnvironment = commonConfig.CLI_ENV === 'cli'; export const CONFIG_DIR = isCliEnvironment ? path.join(os.homedir(), '.prompt-library-cli') diff --git a/src/shared/config/index.ts b/src/shared/config/index.ts index 18d9602..cf2518d 100644 --- a/src/shared/config/index.ts +++ b/src/shared/config/index.ts @@ -1,12 +1,14 @@ import * as fs from 'fs'; -import { commonConfig, CommonConfig } from './common.config'; +import { CommonConfig, commonConfig } from './common.config'; import { CONFIG_DIR, CONFIG_FILE, isCliEnvironment } from './config.constants'; import { AppConfig, appConfig } from '../../app/config/app.config'; import { CliConfig, cliConfig } from '../../cli/config/cli.config'; export type Config = CommonConfig & (CliConfig | AppConfig); +let loadedConfig: Config | null = null; + function loadConfig(): Config { const environmentConfig = isCliEnvironment ? cliConfig : appConfig; let config: Config = { ...commonConfig, ...environmentConfig }; @@ -16,9 +18,7 @@ function loadConfig(): Config { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } - if (!fs.existsSync(CONFIG_FILE)) { - fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2)); - } else { + if (fs.existsSync(CONFIG_FILE)) { const fileConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8')); config = { ...config, ...fileConfig }; } @@ -26,19 +26,53 @@ function loadConfig(): Config { return config; } -const loadedConfig: Config = loadConfig(); +export function setConfig(key: K, value: Config[K]): void { + if (!isCliEnvironment) { + throw new Error('setConfig is only available in CLI environment'); + } + + if (!loadedConfig) { + loadedConfig = loadConfig(); + } + + loadedConfig[key] = value; + + // Update process.env to reflect the change + if (typeof value === 'string') { + process.env[key.toString()] = value; + } + + // Write to file + fs.writeFileSync(CONFIG_FILE, JSON.stringify(loadedConfig, null, 2)); + + // Clear the cache by reassigning loadedConfig to null + loadedConfig = null as unknown as Config; +} export function getConfig(): Readonly { + if (loadedConfig === null) { + loadedConfig = loadConfig(); + } return loadedConfig; } -export function setConfig(key: K, value: Config[K]): void { +export function getConfigValue(key: K): Config[K] { + if (loadedConfig === null) { + loadedConfig = loadConfig(); + } + if (isCliEnvironment) { - loadedConfig[key] = value; - fs.writeFileSync(CONFIG_FILE, JSON.stringify(loadedConfig, null, 2)); + return loadedConfig[key]; } else { - throw new Error('setConfig is only available in CLI environment'); + const envValue = process.env[key.toString()]; + return (envValue !== undefined ? envValue : loadedConfig[key]) as Config[K]; } } -export const config: Readonly = loadedConfig; +type ConfigValue = Config[keyof Config]; + +export const config: Readonly = new Proxy({} as Config, { + get(_, prop: string): ConfigValue { + return getConfigValue(prop as keyof Config); + } +}); diff --git a/src/shared/utils/anthropic_client.ts b/src/shared/utils/anthropic_client.ts index 40054c9..7f0efb6 100644 --- a/src/shared/utils/anthropic_client.ts +++ b/src/shared/utils/anthropic_client.ts @@ -1,12 +1,12 @@ import { Anthropic } from '@anthropic-ai/sdk'; import { Message, MessageStreamEvent } from '@anthropic-ai/sdk/resources'; +import { config, getConfigValue } from '../config'; import logger from './logger'; -import { config } from '../config'; import { commonConfig } from '../config/common.config'; export function initializeAnthropicClient(): Anthropic { - const apiKey = commonConfig.ANTHROPIC_API_KEY; + const apiKey = getConfigValue('ANTHROPIC_API_KEY'); if (!apiKey) { logger.error('ANTHROPIC_API_KEY is not set in the environment.');