english-optimizer-cli 1.0.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.
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROMPT_TEMPLATES = void 0;
4
+ exports.getPromptTemplate = getPromptTemplate;
5
+ exports.getAllModes = getAllModes;
6
+ exports.getModeInfo = getModeInfo;
7
+ const types_1 = require("../types");
8
+ exports.PROMPT_TEMPLATES = {
9
+ [types_1.OptimizationMode.PROFESSIONAL]: {
10
+ name: 'Professional',
11
+ description: 'Make the text sound more professional and formal',
12
+ template: (text) => `Please rewrite the following text to make it sound more professional and formal, while maintaining the original meaning. Use appropriate business language and tone.
13
+
14
+ Original text:
15
+ "${text}"
16
+
17
+ Rewritten text:`,
18
+ },
19
+ [types_1.OptimizationMode.CONCISE]: {
20
+ name: 'Concise',
21
+ description: 'Make the text more concise while keeping the meaning',
22
+ template: (text) => `Please rewrite the following text to be more concise and to the point, while preserving all the key information and meaning.
23
+
24
+ Original text:
25
+ "${text}"
26
+
27
+ Rewritten text:`,
28
+ },
29
+ [types_1.OptimizationMode.GRAMMAR]: {
30
+ name: 'Grammar',
31
+ description: 'Fix grammar and spelling errors only',
32
+ template: (text) => `Please fix any grammar, spelling, or punctuation errors in the following text. Do not change the style or meaning - only correct mistakes.
33
+
34
+ Original text:
35
+ "${text}"
36
+
37
+ Corrected text:`,
38
+ },
39
+ [types_1.OptimizationMode.SENIOR_DEVELOPER]: {
40
+ name: 'Senior Developer',
41
+ description: 'Rewrite as a senior software engineer would write it',
42
+ template: (text) => `Please rewrite the following text as a senior software engineer would write it in a professional context (e.g., code review, technical discussion, or documentation). Use clear, precise technical language and follow industry best practices for communication.
43
+
44
+ Original text:
45
+ "${text}"
46
+
47
+ Rewritten text:`,
48
+ },
49
+ };
50
+ function getPromptTemplate(mode, text) {
51
+ return exports.PROMPT_TEMPLATES[mode].template(text);
52
+ }
53
+ function getAllModes() {
54
+ return Object.values(types_1.OptimizationMode);
55
+ }
56
+ function getModeInfo(mode) {
57
+ return exports.PROMPT_TEMPLATES[mode];
58
+ }
59
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TranslationPromptLoader = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ class TranslationPromptLoader {
8
+ constructor(promptPath) {
9
+ this.promptPath = promptPath || (0, path_1.join)((0, os_1.homedir)(), '.english-optimizer', 'translation-prompt.txt');
10
+ }
11
+ getPrompt() {
12
+ if ((0, fs_1.existsSync)(this.promptPath)) {
13
+ try {
14
+ return (0, fs_1.readFileSync)(this.promptPath, 'utf-8');
15
+ }
16
+ catch {
17
+ // Fall back to default
18
+ return this.getDefaultPrompt();
19
+ }
20
+ }
21
+ // Create default prompt file
22
+ this.createDefaultPromptFile();
23
+ return this.getDefaultPrompt();
24
+ }
25
+ getDefaultPrompt() {
26
+ return `You are a professional translator and editor for software developers.
27
+
28
+ Your task is to:
29
+ 1. Detect if the text is Chinese or English
30
+ 2. If Chinese: Translate to natural, professional English
31
+ 3. If English: Optimize the English to be more natural and professional
32
+ 4. Use terminology and phrasing common in software development
33
+ 5. Make it sound like a native English-speaking developer
34
+ 6. Preserve technical terms, API names, and code snippets
35
+ 7. For multi-line text, maintain the paragraph structure
36
+
37
+ Text to process:
38
+ "{text}"
39
+
40
+ Provide ONLY the translated/optimized English text, nothing else.
41
+ Do not include any explanations, notes, or additional text.`;
42
+ }
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 });
49
+ }
50
+ writeFileSync(this.promptPath, this.getDefaultPrompt(), 'utf-8');
51
+ }
52
+ getPromptPath() {
53
+ return this.promptPath;
54
+ }
55
+ }
56
+ exports.TranslationPromptLoader = TranslationPromptLoader;
57
+ //# sourceMappingURL=translation-prompt.js.map
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.YAMLPromptLoader = void 0;
37
+ const fs_1 = require("fs");
38
+ const path_1 = require("path");
39
+ const yaml = __importStar(require("js-yaml"));
40
+ class YAMLPromptLoader {
41
+ constructor(promptPath) {
42
+ this.promptPath = promptPath || (0, path_1.join)(process.cwd(), 'prompt.yaml');
43
+ }
44
+ loadConfig() {
45
+ if (!(0, fs_1.existsSync)(this.promptPath)) {
46
+ return null;
47
+ }
48
+ try {
49
+ const content = (0, fs_1.readFileSync)(this.promptPath, 'utf-8');
50
+ const config = yaml.load(content);
51
+ return config;
52
+ }
53
+ catch (error) {
54
+ console.warn('Failed to load YAML prompt config:', error);
55
+ return null;
56
+ }
57
+ }
58
+ buildPrompt(text) {
59
+ const config = this.loadConfig();
60
+ if (!config) {
61
+ throw new Error('YAML prompt config not found');
62
+ }
63
+ const sections = [];
64
+ sections.push(`## Role\n${config.role.name}\n${config.role.description}`);
65
+ if (config.goals && config.goals.length > 0) {
66
+ sections.push(`## Goals\n${config.goals.map((g) => `- ${g}`).join('\n')}`);
67
+ }
68
+ if (config.user_profile) {
69
+ sections.push(`## User Profile\n` +
70
+ `Background: ${config.user_profile.background}\n` +
71
+ `Native Language: ${config.user_profile.native_language}\n` +
72
+ `Learning Goal: ${config.user_profile.learning_goal}`);
73
+ }
74
+ if (config.instructions && config.instructions.length > 0) {
75
+ sections.push(`## Instructions\n${config.instructions.map((i) => `- ${i}`).join('\n')}`);
76
+ }
77
+ if (config.output_format) {
78
+ sections.push(`## Output Format\n` +
79
+ `Style: ${config.output_format.style}\n` +
80
+ `Structure: ${config.output_format.structure.join(', ')}`);
81
+ }
82
+ if (config.examples && config.examples.length > 0) {
83
+ sections.push(`## Examples\n` +
84
+ config.examples.map((ex) => `Input: "${ex.input}"\nOutput: ${ex.output}`).join('\n\n'));
85
+ }
86
+ if (config.constraints && config.constraints.length > 0) {
87
+ sections.push(`## Constraints\n${config.constraints.map((c) => `- ${c}`).join('\n')}`);
88
+ }
89
+ sections.push(`\n## Input to Optimize\n"${text}"`);
90
+ sections.push('\n## Output\nProvide ONLY the optimized English text, nothing else.');
91
+ return sections.join('\n\n');
92
+ }
93
+ hasYAMLPrompt() {
94
+ return this.loadConfig() !== null;
95
+ }
96
+ getPromptPath() {
97
+ return this.promptPath;
98
+ }
99
+ }
100
+ exports.YAMLPromptLoader = YAMLPromptLoader;
101
+ //# sourceMappingURL=yaml-prompt.js.map
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OptimizationMode = void 0;
4
+ var OptimizationMode;
5
+ (function (OptimizationMode) {
6
+ OptimizationMode["PROFESSIONAL"] = "professional";
7
+ OptimizationMode["CONCISE"] = "concise";
8
+ OptimizationMode["GRAMMAR"] = "grammar";
9
+ OptimizationMode["SENIOR_DEVELOPER"] = "senior_developer";
10
+ })(OptimizationMode || (exports.OptimizationMode = OptimizationMode = {}));
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.displayWelcome = displayWelcome;
7
+ exports.displayModeInfo = displayModeInfo;
8
+ exports.displayOptimization = displayOptimization;
9
+ exports.displayDiff = displayDiff;
10
+ exports.displayError = displayError;
11
+ exports.displaySuccess = displaySuccess;
12
+ exports.displayInfo = displayInfo;
13
+ exports.displayWarning = displayWarning;
14
+ exports.displayHelp = displayHelp;
15
+ exports.displayHistoryEntry = displayHistoryEntry;
16
+ const chalk_1 = __importDefault(require("chalk"));
17
+ const diff_1 = require("diff");
18
+ const templates_1 = require("../prompts/templates");
19
+ function displayWelcome() {
20
+ console.log(chalk_1.default.cyan.bold('\n🚀 English Optimizer CLI\n'));
21
+ }
22
+ function displayModeInfo(mode) {
23
+ const modeInfo = (0, templates_1.getModeInfo)(mode);
24
+ console.log(chalk_1.default.yellow(`\n[${modeInfo.name} Mode]`));
25
+ console.log(chalk_1.default.gray(modeInfo.description));
26
+ }
27
+ 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)));
36
+ }
37
+ function displayDiff(original, optimized) {
38
+ const differences = (0, diff_1.diffLines)(original, optimized);
39
+ differences.forEach((part) => {
40
+ const color = part.added ? chalk_1.default.green : part.removed ? chalk_1.default.red : chalk_1.default.gray;
41
+ const prefix = part.added ? '+ ' : part.removed ? '- ' : ' ';
42
+ process.stdout.write(color(prefix + part.value));
43
+ });
44
+ console.log();
45
+ }
46
+ function displayError(error) {
47
+ const message = typeof error === 'string' ? error : error.message;
48
+ console.log(chalk_1.default.red('\n❌ Error:'), chalk_1.default.white(message));
49
+ }
50
+ function displaySuccess(message) {
51
+ console.log(chalk_1.default.green('\n✅'), chalk_1.default.white(message));
52
+ }
53
+ function displayInfo(message) {
54
+ console.log(chalk_1.default.cyan('\nℹ️'), chalk_1.default.white(message));
55
+ }
56
+ function displayWarning(message) {
57
+ console.log(chalk_1.default.yellow('\n⚠️'), chalk_1.default.white(message));
58
+ }
59
+ function displayHelp() {
60
+ console.log(chalk_1.default.cyan('\n📖 Hotkeys:\n'));
61
+ console.log(chalk_1.default.gray(' Ctrl+P - Professional tone'));
62
+ console.log(chalk_1.default.gray(' Ctrl+C - Concise version'));
63
+ console.log(chalk_1.default.gray(' Ctrl+G - Grammar fix'));
64
+ console.log(chalk_1.default.gray(' Ctrl+D - Senior developer style'));
65
+ console.log(chalk_1.default.gray(' Ctrl+R - Reset to original'));
66
+ console.log(chalk_1.default.gray(' Ctrl+H - View history'));
67
+ console.log(chalk_1.default.gray(' Ctrl+Q - Quit\n'));
68
+ }
69
+ function displayHistoryEntry(entry) {
70
+ console.log(chalk_1.default.gray('\n' + '─'.repeat(60)));
71
+ console.log(chalk_1.default.cyan(`\nID: ${entry.id}`));
72
+ console.log(chalk_1.default.gray(`Time: ${entry.timestamp.toLocaleString()}`));
73
+ console.log(chalk_1.default.yellow(`Mode: ${(0, templates_1.getModeInfo)(entry.mode).name}`));
74
+ console.log(chalk_1.default.red('\n❌ Original:'));
75
+ console.log(chalk_1.default.gray(entry.original));
76
+ 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)));
79
+ }
80
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1,22 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ ollama:
5
+ image: ollama/ollama:latest
6
+ container_name: english-optimizer-ollama
7
+ ports:
8
+ - "11434:11434"
9
+ volumes:
10
+ - ollama_data:/root/.ollama
11
+ environment:
12
+ - OLLAMA_HOST=0.0.0.0
13
+ restart: unless-stopped
14
+ healthcheck:
15
+ test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
16
+ interval: 30s
17
+ timeout: 10s
18
+ retries: 5
19
+
20
+ volumes:
21
+ ollama_data:
22
+ driver: local
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "english-optimizer-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool to help non-native English speakers improve their writing using AI",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "fuck-abc": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "ts-node src/index.ts",
13
+ "watch": "tsc --watch",
14
+ "install-config": "node scripts/install-config.js"
15
+ },
16
+ "keywords": [
17
+ "cli",
18
+ "english",
19
+ "learning",
20
+ "ai",
21
+ "optimizer"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "axios": "^1.6.0",
27
+ "chalk": "^5.3.0",
28
+ "cli-cursor": "^4.0.0",
29
+ "clipboardy": "^3.0.0",
30
+ "commander": "^12.0.0",
31
+ "diff": "^5.1.0",
32
+ "dotenv": "^16.3.0",
33
+ "inquirer": "^9.2.0",
34
+ "js-yaml": "^4.1.0",
35
+ "keypress": "^0.2.1",
36
+ "ora": "^8.0.0",
37
+ "uuid": "^9.0.0",
38
+ "zod": "^3.22.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/diff": "^5.0.0",
42
+ "@types/inquirer": "^9.0.0",
43
+ "@types/js-yaml": "^4.0.9",
44
+ "@types/node": "^20.10.0",
45
+ "@types/uuid": "^9.0.0",
46
+ "eslint": "^8.55.0",
47
+ "prettier": "^3.1.0",
48
+ "ts-node": "^10.9.0",
49
+ "typescript": "^5.3.0"
50
+ },
51
+ "engines": {
52
+ "node": ">=18.0.0"
53
+ }
54
+ }
package/prompt.yaml ADDED
@@ -0,0 +1,48 @@
1
+ role:
2
+ name: Native English Full-Stack Engineer Coach
3
+ description: >
4
+ You are a senior full-stack software engineer who is a native English speaker.
5
+ You have strong experience in frontend, backend, system design, and real-world
6
+ engineering collaboration. You communicate naturally, clearly, and professionally,
7
+ just like in daily standups, design reviews, and team discussions.
8
+
9
+ goals:
10
+ - Help the user learn natural, spoken English used by software engineers
11
+ - Translate the user's input into idiomatic, native-level English
12
+ - Optimize wording to sound natural, confident, and professional
13
+ - Match the tone of real workplace communication (meetings, chats, reviews)
14
+
15
+ user_profile:
16
+ background: Software Engineer
17
+ native_language: Chinese
18
+ learning_goal: Improve practical English for daily engineering communication
19
+
20
+ instructions:
21
+ - Always assume the user wants to improve their English, not just get a literal translation
22
+ - Rewrite the input in a way a native English-speaking engineer would naturally say it
23
+ - Prefer conversational, work-friendly language over academic or overly formal English
24
+ - Keep sentences concise and clear, like real team communication
25
+ - Avoid textbook-style translations or unnatural phrasing
26
+ - If multiple natural expressions are possible, choose the most commonly used one
27
+
28
+ output_format:
29
+ style: >
30
+ Natural, spoken English commonly used in engineering teams.
31
+ Sounds like real conversations in meetings, Slack, or code reviews.
32
+ structure:
33
+ - Optimized English version
34
+ - (Optional) A brief explanation of why this phrasing is more natural
35
+
36
+ examples:
37
+ - input: '这个需求我已经完成了,但是还需要再测试一下'
38
+ output: >
39
+ I've finished this feature, but I still need to do some more testing.
40
+
41
+ - input: '这个问题我稍后再跟进'
42
+ output: >
43
+ I'll follow up on this later.
44
+
45
+ constraints:
46
+ - Do not over-explain unless the user explicitly asks
47
+ - Do not change the original meaning
48
+ - Do not use overly complex vocabulary unless it fits real engineering conversations