english-optimizer-cli 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SECURITY.md ADDED
@@ -0,0 +1,53 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ We release patches for security vulnerabilities for the following versions:
6
+
7
+ | Version | Supported |
8
+ | ------- | ------------------ |
9
+ | 1.5.x | :white_check_mark: |
10
+ | < 1.5 | :x: |
11
+
12
+ ## Reporting a Vulnerability
13
+
14
+ We take the security of English Optimizer CLI seriously. If you believe you have found a security vulnerability, please report it to us as described below.
15
+
16
+ **Please do not report security vulnerabilities through public GitHub issues.**
17
+
18
+ Instead, please report them via email to:
19
+ - Create a private security advisory on GitHub: https://github.com/[your-username]/english-optimizer-cli/security/advisories/new
20
+
21
+ Please include the following information:
22
+ - Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
23
+ - Full paths of source file(s) related to the manifestation of the issue
24
+ - The location of the affected source code (tag/branch/commit or direct URL)
25
+ - Any special configuration required to reproduce the issue
26
+ - Step-by-step instructions to reproduce the issue
27
+ - Proof-of-concept or exploit code (if possible)
28
+ - Impact of the issue, including how an attacker might exploit it
29
+
30
+ ## What to Expect
31
+
32
+ - You will receive a response from us within 48 hours
33
+ - We will work with you to understand and validate the issue
34
+ - We will develop and release a fix as quickly as possible
35
+ - We will publicly acknowledge your responsible disclosure, if you wish
36
+
37
+ ## Security Best Practices for Users
38
+
39
+ When using English Optimizer CLI:
40
+
41
+ 1. **API Keys**: Never commit API keys to version control. Use `.env` files (which are gitignored by default)
42
+ 2. **Updates**: Keep the CLI updated to the latest version to get security patches
43
+ 3. **Permissions**: Be cautious when granting file system permissions
44
+ 4. **Network**: If using cloud APIs, ensure you're using HTTPS endpoints
45
+ 5. **Dependencies**: Regularly check for and update dependencies with known vulnerabilities
46
+
47
+ ## Known Security Considerations
48
+
49
+ - API keys are stored in plain text in configuration files (`~/.english-optimizer/config.yaml` or `.env`)
50
+ - Ensure proper file permissions on configuration files containing API keys
51
+ - Be cautious when sharing history files as they may contain sensitive text
52
+
53
+ Thank you for helping keep English Optimizer CLI and its users safe!
@@ -5,66 +5,43 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ApiProvider = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
+ const chalk_1 = __importDefault(require("chalk"));
8
9
  const templates_1 = require("../prompts/templates");
9
10
  class ApiProvider {
10
11
  constructor(config) {
11
12
  this.config = config;
12
13
  }
13
- async optimize(text, mode) {
14
- const prompt = (0, templates_1.getPromptTemplate)(mode, text);
15
- try {
16
- const response = await axios_1.default.post(`${this.config.baseUrl}/chat/completions`, {
17
- model: this.config.model,
18
- messages: [
19
- {
20
- role: 'user',
21
- content: prompt,
22
- },
23
- ],
24
- temperature: 0.7,
25
- max_tokens: 2000,
26
- }, {
27
- headers: {
28
- 'Authorization': `Bearer ${this.config.apiKey}`,
29
- 'Content-Type': 'application/json',
30
- },
31
- timeout: 60000, // 60 seconds timeout
32
- });
33
- if (response.data && response.data.choices && response.data.choices.length > 0) {
34
- let result = response.data.choices[0].message.content.trim();
35
- // Remove quotes if the model wrapped the response in them
36
- if (result.startsWith('"') && result.endsWith('"')) {
37
- result = result.slice(1, -1);
14
+ handleApiError(error) {
15
+ if (axios_1.default.isAxiosError(error)) {
16
+ const axiosError = error;
17
+ if (axiosError.response) {
18
+ const status = axiosError.response.status;
19
+ const data = axiosError.response.data;
20
+ // Handle GLM specific errors
21
+ if (data?.error?.code === '1113') {
22
+ throw new Error('GLM account balance is insufficient. Please recharge your account at https://open.bigmodel.cn/usercenter/finance');
38
23
  }
39
- // Remove common prefixes if present
40
- const prefixesToRemove = ['Rewritten text:', 'Corrected text:', 'Optimized text:'];
41
- for (const prefix of prefixesToRemove) {
42
- if (result.startsWith(prefix)) {
43
- result = result.slice(prefix.length).trim();
44
- }
24
+ if (status === 401) {
25
+ throw new Error('Invalid API key. Please check your API credentials.');
45
26
  }
46
- return result;
47
- }
48
- throw new Error('Invalid response from API');
49
- }
50
- catch (error) {
51
- if (axios_1.default.isAxiosError(error)) {
52
- const axiosError = error;
53
- if (axiosError.response) {
54
- const status = axiosError.response.status;
55
- if (status === 401) {
56
- throw new Error('Invalid API key. Please check your API credentials.');
57
- }
58
- else if (status === 429) {
59
- throw new Error('Rate limit exceeded. Please try again later.');
60
- }
27
+ else if (status === 429) {
28
+ throw new Error('Rate limit exceeded. Please try again later.');
61
29
  }
62
- throw new Error(`API error: ${axiosError.message}`);
63
30
  }
64
- throw error;
31
+ throw new Error(`API error: ${axiosError.message}`);
65
32
  }
33
+ throw error;
34
+ }
35
+ async optimize(text, mode) {
36
+ const prompt = (0, templates_1.getPromptTemplate)(mode, text);
37
+ const result = await this.callAPI(prompt);
38
+ return this.cleanupResponse(result, true);
66
39
  }
67
40
  async generateWithPrompt(prompt) {
41
+ const result = await this.callAPI(prompt);
42
+ return this.cleanupResponse(result, false);
43
+ }
44
+ async callAPI(prompt) {
68
45
  try {
69
46
  const response = await axios_1.default.post(`${this.config.baseUrl}/chat/completions`, {
70
47
  model: this.config.model,
@@ -78,58 +55,77 @@ class ApiProvider {
78
55
  max_tokens: 2000,
79
56
  }, {
80
57
  headers: {
81
- 'Authorization': `Bearer ${this.config.apiKey}`,
58
+ Authorization: `Bearer ${this.config.apiKey}`,
82
59
  'Content-Type': 'application/json',
83
60
  },
84
61
  timeout: 60000,
85
62
  });
86
63
  if (response.data && response.data.choices && response.data.choices.length > 0) {
87
- let result = response.data.choices[0].message.content.trim();
88
- // Remove quotes if the model wrapped the response in them
89
- if (result.startsWith('"') && result.endsWith('"')) {
90
- result = result.slice(1, -1);
91
- }
92
- return result;
64
+ return response.data.choices[0].message.content.trim();
93
65
  }
94
66
  throw new Error('Invalid response from API');
95
67
  }
96
68
  catch (error) {
97
- if (axios_1.default.isAxiosError(error)) {
98
- const axiosError = error;
99
- if (axiosError.response) {
100
- const status = axiosError.response.status;
101
- if (status === 401) {
102
- throw new Error('Invalid API key. Please check your API credentials.');
103
- }
104
- else if (status === 429) {
105
- throw new Error('Rate limit exceeded. Please try again later.');
106
- }
69
+ this.handleApiError(error);
70
+ }
71
+ }
72
+ cleanupResponse(result, removePrefixes) {
73
+ // Remove quotes if model wrapped the response in them
74
+ if (result.startsWith('"') && result.endsWith('"')) {
75
+ result = result.slice(1, -1);
76
+ }
77
+ // Remove common prefixes if present
78
+ if (removePrefixes) {
79
+ const prefixesToRemove = ['Rewritten text:', 'Corrected text:', 'Optimized text:'];
80
+ for (const prefix of prefixesToRemove) {
81
+ if (result.startsWith(prefix)) {
82
+ result = result.slice(prefix.length).trim();
83
+ break;
107
84
  }
108
- throw new Error(`API error: ${axiosError.message}`);
109
85
  }
110
- throw error;
111
86
  }
87
+ return result;
112
88
  }
113
89
  async isAvailable() {
114
90
  if (!this.config.apiKey) {
115
91
  return false;
116
92
  }
117
93
  try {
118
- // Try a simple API call to check if the key is valid
94
+ // Try a simple API call to check if key is valid
119
95
  const response = await axios_1.default.post(`${this.config.baseUrl}/chat/completions`, {
120
96
  model: this.config.model,
121
97
  messages: [{ role: 'user', content: 'test' }],
122
98
  max_tokens: 5,
123
99
  }, {
124
100
  headers: {
125
- 'Authorization': `Bearer ${this.config.apiKey}`,
101
+ Authorization: `Bearer ${this.config.apiKey}`,
126
102
  'Content-Type': 'application/json',
127
103
  },
128
104
  timeout: 10000,
129
105
  });
130
106
  return response.status === 200;
131
107
  }
132
- catch {
108
+ catch (error) {
109
+ if (error.response) {
110
+ console.log('\n' + chalk_1.default.yellow('API connection failed with status:'), error.response.status);
111
+ if (error.response.data) {
112
+ console.log(chalk_1.default.yellow('Error details:'), JSON.stringify(error.response.data));
113
+ // Throw error for GLM balance issues
114
+ if (error.response.data?.error?.code === '1113') {
115
+ throw new Error('GLM account balance is insufficient. Please recharge your account at https://open.bigmodel.cn/usercenter/finance');
116
+ }
117
+ }
118
+ }
119
+ else if (error.request) {
120
+ console.log('\n' + chalk_1.default.yellow('No response from API'));
121
+ console.log(chalk_1.default.gray('Possible issues:'));
122
+ console.log(chalk_1.default.gray(' - Network connectivity'));
123
+ console.log(chalk_1.default.gray(' - API URL is incorrect'));
124
+ console.log(chalk_1.default.gray(' - Firewall blocking the request'));
125
+ }
126
+ else {
127
+ console.log('\n' + chalk_1.default.yellow('Request setup error:'), error.message);
128
+ }
133
129
  return false;
134
130
  }
135
131
  }
package/dist/ai/ollama.js CHANGED
@@ -12,33 +12,28 @@ class OllamaProvider {
12
12
  }
13
13
  async optimize(text, mode) {
14
14
  const prompt = (0, templates_1.getPromptTemplate)(mode, text);
15
+ const result = await this.callOllama(prompt);
16
+ return this.cleanupResponse(result, true);
17
+ }
18
+ async generateWithPrompt(prompt) {
19
+ const result = await this.callOllama(prompt);
20
+ return this.cleanupResponse(result, false);
21
+ }
22
+ async callOllama(prompt) {
15
23
  try {
16
24
  const response = await axios_1.default.post(`${this.config.baseUrl}/api/generate`, {
17
25
  model: this.config.model,
18
- prompt: prompt,
26
+ prompt,
19
27
  stream: false,
20
28
  options: {
21
29
  temperature: 0.7,
22
30
  top_p: 0.9,
23
31
  },
24
32
  }, {
25
- timeout: 60000, // 60 seconds timeout
33
+ timeout: 60000,
26
34
  });
27
35
  if (response.data && response.data.response) {
28
- // Extract the optimized text from the response
29
- let result = response.data.response.trim();
30
- // Remove quotes if the model wrapped the response in them
31
- if (result.startsWith('"') && result.endsWith('"')) {
32
- result = result.slice(1, -1);
33
- }
34
- // Remove common prefixes if present
35
- const prefixesToRemove = ['Rewritten text:', 'Corrected text:', 'Optimized text:'];
36
- for (const prefix of prefixesToRemove) {
37
- if (result.startsWith(prefix)) {
38
- result = result.slice(prefix.length).trim();
39
- }
40
- }
41
- return result;
36
+ return response.data.response.trim();
42
37
  }
43
38
  throw new Error('Invalid response from Ollama');
44
39
  }
@@ -53,39 +48,22 @@ class OllamaProvider {
53
48
  throw error;
54
49
  }
55
50
  }
56
- async generateWithPrompt(prompt) {
57
- try {
58
- const response = await axios_1.default.post(`${this.config.baseUrl}/api/generate`, {
59
- model: this.config.model,
60
- prompt: prompt,
61
- stream: false,
62
- options: {
63
- temperature: 0.7,
64
- top_p: 0.9,
65
- },
66
- }, {
67
- timeout: 60000,
68
- });
69
- if (response.data && response.data.response) {
70
- let result = response.data.response.trim();
71
- // Remove quotes if the model wrapped the response in them
72
- if (result.startsWith('"') && result.endsWith('"')) {
73
- result = result.slice(1, -1);
74
- }
75
- return result;
76
- }
77
- throw new Error('Invalid response from Ollama');
51
+ cleanupResponse(result, removePrefixes) {
52
+ // Remove quotes if the model wrapped the response in them
53
+ if (result.startsWith('"') && result.endsWith('"')) {
54
+ result = result.slice(1, -1);
78
55
  }
79
- catch (error) {
80
- if (axios_1.default.isAxiosError(error)) {
81
- const axiosError = error;
82
- if (axiosError.code === 'ECONNREFUSED') {
83
- throw new Error(`Cannot connect to Ollama at ${this.config.baseUrl}. Make sure Ollama is running.`);
56
+ // Remove common prefixes if present
57
+ if (removePrefixes) {
58
+ const prefixesToRemove = ['Rewritten text:', 'Corrected text:', 'Optimized text:'];
59
+ for (const prefix of prefixesToRemove) {
60
+ if (result.startsWith(prefix)) {
61
+ result = result.slice(prefix.length).trim();
62
+ break;
84
63
  }
85
- throw new Error(`Ollama API error: ${axiosError.message}`);
86
64
  }
87
- throw error;
88
65
  }
66
+ return result;
89
67
  }
90
68
  async isAvailable() {
91
69
  try {
@@ -111,10 +111,8 @@ class ConfigManager {
111
111
  }
112
112
  loadConfig() {
113
113
  // Try to load from YAML config file first, then JSON
114
- let configFilePath = null;
115
114
  let fileContent = '';
116
115
  if ((0, fs_1.existsSync)(CONFIG_FILE_YAML)) {
117
- configFilePath = CONFIG_FILE_YAML;
118
116
  try {
119
117
  fileContent = (0, fs_1.readFileSync)(CONFIG_FILE_YAML, 'utf-8');
120
118
  const fileConfig = yaml.load(fileContent);
@@ -127,7 +125,6 @@ class ConfigManager {
127
125
  }
128
126
  }
129
127
  if ((0, fs_1.existsSync)(CONFIG_FILE_JSON)) {
130
- configFilePath = CONFIG_FILE_JSON;
131
128
  try {
132
129
  fileContent = (0, fs_1.readFileSync)(CONFIG_FILE_JSON, 'utf-8');
133
130
  const fileConfig = JSON.parse(fileContent);
@@ -25,7 +25,22 @@ async function testConfiguration() {
25
25
  }
26
26
  console.log(chalk_1.default.gray('\n' + '─'.repeat(50) + '\n'));
27
27
  console.log(chalk_1.default.cyan('šŸ”„ Testing connection...\n'));
28
- const isAvailable = await provider.isAvailable();
28
+ let isAvailable = false;
29
+ try {
30
+ isAvailable = await provider.isAvailable();
31
+ }
32
+ catch (e) {
33
+ if (e.message.includes('balance is insufficient')) {
34
+ console.log(chalk_1.default.red.bold('\nāŒ GLM Account Balance Issue!\n'));
35
+ console.log(chalk_1.default.yellow('Your GLM account has insufficient balance.\n'));
36
+ console.log(chalk_1.default.cyan('šŸ’” To fix:'));
37
+ console.log(chalk_1.default.white(' 1. Visit https://open.bigmodel.cn/usercenter/finance'));
38
+ console.log(chalk_1.default.white(' 2. Recharge your account'));
39
+ console.log(chalk_1.default.white(' 3. Run test again: fuck-abc test\n'));
40
+ process.exit(1);
41
+ }
42
+ throw e;
43
+ }
29
44
  if (isAvailable) {
30
45
  console.log(chalk_1.default.green.bold('āœ… API configuration is valid!\n'));
31
46
  if (config.ai.provider === 'api') {
@@ -109,7 +109,7 @@ class InstantEditor {
109
109
  clipboardy_1.default.writeSync(optimized);
110
110
  console.log(chalk_1.default.green.bold('\nāœ“ å·²å¤åˆ¶åˆ°å‰Ŗč““ęæ / Copied to clipboard!\n'));
111
111
  }
112
- catch (error) {
112
+ catch {
113
113
  console.log(chalk_1.default.yellow('\nāš ļø å‰Ŗč““ęæå¤åˆ¶å¤±č“„ / Failed to copy to clipboard\n'));
114
114
  }
115
115
  // Save to history
@@ -12,22 +12,8 @@ class Optimizer {
12
12
  }
13
13
  }
14
14
  async optimize(text, mode) {
15
- const startTime = Date.now();
16
15
  const optimized = await this.provider.optimize(text, mode);
17
- const duration = Date.now() - startTime;
18
- const result = {
19
- original: text,
20
- optimized,
21
- mode,
22
- timestamp: new Date(),
23
- provider: this.getProviderName(),
24
- model: this.getModelName(),
25
- };
26
- // Save to history if enabled
27
- if (this.historyLogger) {
28
- this.historyLogger.addEntry(result);
29
- }
30
- return result;
16
+ return this.createResult(text, optimized, mode);
31
17
  }
32
18
  async optimizeWithYAMLPrompt(text) {
33
19
  if (!this.yamlPromptLoader || !this.yamlPromptLoader.hasYAMLPrompt()) {
@@ -35,10 +21,20 @@ class Optimizer {
35
21
  }
36
22
  const prompt = this.yamlPromptLoader.buildPrompt(text);
37
23
  const optimized = await this.provider.generateWithPrompt(prompt);
24
+ return this.createResult(text, optimized, types_1.OptimizationMode.PROFESSIONAL);
25
+ }
26
+ hasYAMLPrompt() {
27
+ return this.yamlPromptLoader?.hasYAMLPrompt() || false;
28
+ }
29
+ async optimizeWithCustomPrompt(text, _customPrompt) {
30
+ const optimized = await this.provider.optimize(text, types_1.OptimizationMode.PROFESSIONAL);
31
+ return this.createResult(text, optimized, types_1.OptimizationMode.PROFESSIONAL);
32
+ }
33
+ createResult(original, optimized, mode) {
38
34
  const result = {
39
- original: text,
35
+ original,
40
36
  optimized,
41
- mode: types_1.OptimizationMode.PROFESSIONAL,
37
+ mode,
42
38
  timestamp: new Date(),
43
39
  provider: this.getProviderName(),
44
40
  model: this.getModelName(),
@@ -49,20 +45,6 @@ class Optimizer {
49
45
  }
50
46
  return result;
51
47
  }
52
- hasYAMLPrompt() {
53
- return this.yamlPromptLoader?.hasYAMLPrompt() || false;
54
- }
55
- async optimizeWithCustomPrompt(text, customPrompt) {
56
- const optimized = await this.provider.optimize(text, types_1.OptimizationMode.PROFESSIONAL);
57
- return {
58
- original: text,
59
- optimized,
60
- mode: types_1.OptimizationMode.PROFESSIONAL,
61
- timestamp: new Date(),
62
- provider: this.getProviderName(),
63
- model: this.getModelName(),
64
- };
65
- }
66
48
  getProviderName() {
67
49
  return this.provider.constructor.name;
68
50
  }
package/dist/index.js CHANGED
@@ -40,6 +40,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  const commander_1 = require("commander");
41
41
  const chalk_1 = __importDefault(require("chalk"));
42
42
  const axios_1 = __importDefault(require("axios"));
43
+ const child_process_1 = require("child_process");
43
44
  const config_1 = require("./config/config");
44
45
  const provider_1 = require("./ai/provider");
45
46
  const optimizer_1 = require("./core/optimizer");
@@ -49,11 +50,12 @@ const batch_1 = require("./core/batch");
49
50
  const logger_1 = require("./history/logger");
50
51
  const custom_1 = require("./prompts/custom");
51
52
  const display_1 = require("./utils/display");
53
+ const package_json_1 = __importDefault(require("../package.json"));
52
54
  const PACKAGE_NAME = 'english-optimizer-cli';
53
- const PACKAGE_VERSION = require('../package.json').version;
55
+ const PACKAGE_VERSION = package_json_1.default.version;
54
56
  const program = new commander_1.Command();
55
57
  program
56
- .name('fuck-abc')
58
+ .name('cao')
57
59
  .description('CLI tool to help non-native English speakers improve their writing using AI')
58
60
  .version(PACKAGE_VERSION);
59
61
  program
@@ -210,13 +212,12 @@ program
210
212
  }
211
213
  }
212
214
  else if (options.edit) {
213
- const { execSync } = require('child_process');
214
215
  const promptPath = hasYAMLPrompt
215
216
  ? yamlPromptLoader.getPromptPath()
216
217
  : textPromptLoader.getPromptPath();
217
218
  console.log(`\nšŸ“ Opening ${promptPath} in your default editor...\n`);
218
219
  try {
219
- execSync(`"${process.env.EDITOR || 'code'}" "${promptPath}"`, { stdio: 'inherit' });
220
+ (0, child_process_1.execSync)(`"${process.env.EDITOR || 'code'}" "${promptPath}"`, { stdio: 'inherit' });
220
221
  }
221
222
  catch {
222
223
  console.log(chalk_1.default.yellow('\nāš ļø Could not open editor. Please edit manually:'));
@@ -232,8 +233,8 @@ program
232
233
  console.log(`\nšŸ“„ Prompt file location: ${textPromptLoader.getPromptPath()}`);
233
234
  }
234
235
  console.log(chalk_1.default.gray('\nCommands:'));
235
- console.log(' fuck-abc prompt --show Show current prompt');
236
- console.log(' fuck-abc prompt --edit Edit prompt file');
236
+ console.log(' cao prompt --show Show current prompt');
237
+ console.log(' cao prompt --edit Edit prompt file');
237
238
  console.log(chalk_1.default.gray('\nEdit the file directly to customize translation behavior.\n'));
238
239
  }
239
240
  }
@@ -292,7 +293,7 @@ program
292
293
  try {
293
294
  console.log(chalk_1.default.cyan('\nšŸ”„ Checking for updates...\n'));
294
295
  // Get current version
295
- const { version: currentVersion } = require('../package.json');
296
+ const currentVersion = package_json_1.default.version;
296
297
  // Fetch latest version from npm
297
298
  try {
298
299
  const response = await axios_1.default.get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
@@ -310,7 +311,7 @@ program
310
311
  console.log(chalk_1.default.gray(' npm install -g english-optimizer-cli@latest\n'));
311
312
  }
312
313
  }
313
- catch (error) {
314
+ catch {
314
315
  console.log(chalk_1.default.yellow('āš ļø Could not check for updates.\n'));
315
316
  console.log(chalk_1.default.gray('Please check manually:'));
316
317
  console.log(chalk_1.default.gray(' npm view english-optimizer-cli version\n'));
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROMPT_TEMPLATES = void 0;
4
4
  exports.getPromptTemplate = getPromptTemplate;
5
- exports.getAllModes = getAllModes;
6
5
  exports.getModeInfo = getModeInfo;
7
6
  const types_1 = require("../types");
8
7
  exports.PROMPT_TEMPLATES = {
@@ -50,9 +49,6 @@ Rewritten text:`,
50
49
  function getPromptTemplate(mode, text) {
51
50
  return exports.PROMPT_TEMPLATES[mode].template(text);
52
51
  }
53
- function getAllModes() {
54
- return Object.values(types_1.OptimizationMode);
55
- }
56
52
  function getModeInfo(mode) {
57
53
  return exports.PROMPT_TEMPLATES[mode];
58
54
  }
@@ -41,13 +41,11 @@ Provide ONLY the translated/optimized English text, nothing else.
41
41
  Do not include any explanations, notes, or additional text.`;
42
42
  }
43
43
  createDefaultPromptFile() {
44
- const { dirname } = require('path');
45
- const { mkdirSync, writeFileSync } = require('fs');
46
- const dir = require('path').dirname(this.promptPath);
47
- if (!require('fs').existsSync(dir)) {
48
- mkdirSync(dir, { recursive: true });
44
+ const dir = (0, path_1.dirname)(this.promptPath);
45
+ if (!(0, fs_1.existsSync)(dir)) {
46
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
49
47
  }
50
- writeFileSync(this.promptPath, this.getDefaultPrompt(), 'utf-8');
48
+ (0, fs_1.writeFileSync)(this.promptPath, this.getDefaultPrompt(), 'utf-8');
51
49
  }
52
50
  getPromptPath() {
53
51
  return this.promptPath;
@@ -10,7 +10,6 @@ exports.displayDiff = displayDiff;
10
10
  exports.displayError = displayError;
11
11
  exports.displaySuccess = displaySuccess;
12
12
  exports.displayInfo = displayInfo;
13
- exports.displayWarning = displayWarning;
14
13
  exports.displayHelp = displayHelp;
15
14
  exports.displayHistoryEntry = displayHistoryEntry;
16
15
  const chalk_1 = __importDefault(require("chalk"));
@@ -25,14 +24,9 @@ function displayModeInfo(mode) {
25
24
  console.log(chalk_1.default.gray(modeInfo.description));
26
25
  }
27
26
  function displayOptimization(original, optimized) {
28
- console.log(chalk_1.default.gray('\n' + '─'.repeat(60)));
29
- // Show original
30
- console.log(chalk_1.default.red('\nāŒ Original:'));
31
- console.log(chalk_1.default.gray(original));
32
- // Show optimized
33
- console.log(chalk_1.default.green('\nāœ… Optimized:'));
34
- console.log(chalk_1.default.white(optimized));
35
- console.log(chalk_1.default.gray('\n' + '─'.repeat(60)));
27
+ displaySeparator();
28
+ displayOriginalAndOptimized(original, optimized);
29
+ displaySeparator();
36
30
  }
37
31
  function displayDiff(original, optimized) {
38
32
  const differences = (0, diff_1.diffLines)(original, optimized);
@@ -53,9 +47,6 @@ function displaySuccess(message) {
53
47
  function displayInfo(message) {
54
48
  console.log(chalk_1.default.cyan('\nā„¹ļø'), chalk_1.default.white(message));
55
49
  }
56
- function displayWarning(message) {
57
- console.log(chalk_1.default.yellow('\nāš ļø'), chalk_1.default.white(message));
58
- }
59
50
  function displayHelp() {
60
51
  console.log(chalk_1.default.cyan('\nšŸ“– Hotkeys:\n'));
61
52
  console.log(chalk_1.default.gray(' Ctrl+P - Professional tone'));
@@ -67,14 +58,21 @@ function displayHelp() {
67
58
  console.log(chalk_1.default.gray(' Ctrl+Q - Quit\n'));
68
59
  }
69
60
  function displayHistoryEntry(entry) {
70
- console.log(chalk_1.default.gray('\n' + '─'.repeat(60)));
61
+ displaySeparator();
71
62
  console.log(chalk_1.default.cyan(`\nID: ${entry.id}`));
72
63
  console.log(chalk_1.default.gray(`Time: ${entry.timestamp.toLocaleString()}`));
73
64
  console.log(chalk_1.default.yellow(`Mode: ${(0, templates_1.getModeInfo)(entry.mode).name}`));
65
+ displayOriginalAndOptimized(entry.original, entry.optimized);
66
+ displaySeparator();
67
+ }
68
+ // Helper functions
69
+ function displaySeparator() {
70
+ console.log(chalk_1.default.gray('\n' + '─'.repeat(60)));
71
+ }
72
+ function displayOriginalAndOptimized(original, optimized) {
74
73
  console.log(chalk_1.default.red('\nāŒ Original:'));
75
- console.log(chalk_1.default.gray(entry.original));
74
+ console.log(chalk_1.default.gray(original));
76
75
  console.log(chalk_1.default.green('\nāœ… Optimized:'));
77
- console.log(chalk_1.default.white(entry.optimized));
78
- console.log(chalk_1.default.gray('\n' + '─'.repeat(60)));
76
+ console.log(chalk_1.default.white(optimized));
79
77
  }
80
78
  //# sourceMappingURL=display.js.map
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ // Example test file - you can expand this with actual tests
5
+ (0, vitest_1.describe)('Display Utils', () => {
6
+ (0, vitest_1.it)('should run a simple test', () => {
7
+ (0, vitest_1.expect)(true).toBe(true);
8
+ });
9
+ });
10
+ //# sourceMappingURL=display.test.js.map